Android面试一天一题(1 Day)

作者: goeasyway | 来源:发表于2016-05-16 20:32 被阅读14275次

    前言

    我从2009年开始接触Android开发(SDK1.6),然后一直在Android这条路上痛并快乐地颠簸顽抗至今。一算也有6年光景了,6年中参加过不同公司的面试,也同样面试过不同公司跳槽来的人,想想自己也算Android开发中骨灰级的面霸了。仿佛已老,老是开始回忆一些以前的面试经历,所以干脆写下来,用自己经历给大家展示一下面试者和面试官两个人会怎么对待同一个问题的。

    面试题:知道Service吗,它有几种启动方式?

    这是我印象深刻的一道题,很明显它是我的第一次,那时我去一家公司(暂时叫它T公司吧)面试外派到韩国三星的工作机会。T公司的面试官是一个叫Bely架构师,显然那个时候Android开发是稀缺资源,知道Service那都不得了了,当然Bely也没打算为难我(必竟也工作4年多了,人长得也不错),我轻松对答:

    Service是一个专门在后台处理长时间任务的Android组件,它没有UI。它有两种启动方式,startService和bindService。

    你猜得没错,Bely紧接着问我:这两种启动方式的区别。

    startService只是启动Service,启动它的组件(如Activity)和Service并没有关联,只有当Service调用stopSelf或者其他组件调用stopService服务才会终止。
    bindService方法启动Service,其他组件可以通过回调获取Service的代理对象和Service交互,而这两方也进行了绑定,当启动方销毁时,Service也会自动进行unBind操作,当发现所有绑定都进行了unBind时才会销毁Service。

    这应该是比较关键的区别了,在面试前我刚刚用Serivce做过一个音乐播放器。几年后,我在深圳面试过很多人,他们中有60-70%的人没有使用Service的经验,让我一度感觉得深圳这座城市做Android开发的比较浮躁。因为这儿工作机会太多了,初级的开发者都比较急功近利,不需要在自己身上下太多的功夫也可以找到工作(当然这是片面的认识)。

    当然还有其他的区别,如两种调用对Service生命周期函数影响,面试官也可以就这个问题展开一下。


    当我遇到面试者知道怎么使用Service,也如多年前的我可以自如的答出startService和bindService的区别时,我一般会多问一句:

    Service的onCreate回调函数可以做耗时的操作吗?

    很多人都会说:可以。

    原形毕露,他前面的回答只是在面试前预习了一下面试题而已。如果知道Service的onCreate是在主线程(ActivityThread)中调用的,耗时操作会阻塞UI,我一般再接着问:

    如果需要做耗时的操作,你会怎么做?

    问题便这样展开了,一个人是否真正懂得原理会灵活运用,一下子便能看出来。 当面试者回答到线程和Handler方式时,我会再问一下对方:

    是否知道IntentService,在什么场景下使用IntentService?

    这也是面试官要看的点,真正的项目需要一个开发人员对某个问题有一定的深度,也需要对整个Android的知识点有一定的广度。深度代表这个人对问题认真对待有钻研的精神,广度代表这个人在面对同一个问题时,会更容易从多种可行的方案中选出最合适的一种。

    Service的实际项目中一直被很多人忽略,为什么我一再强调Service很重要,我们来看看,如果对Service完全无知会在工作中遇到什么问题。

    场景:如果一个应用要从网络上下载MP3文件,并在Activity上展示进度条,这个Activity要求是可以转屏的。那么在转屏时Actvitiy会重启,如何保证下载的进度条能正确展示进度呢?

    没有Service概念的人,一般想出来的方案如下:

    1. 在转屏前将进度缓存,转屏后再读出来。
    2. 使用android:configChanges设置,让转屏时Activity不销毁和重建。

    针对第1个方案,我会继续问他将进度值存在哪里? 转屏的过程中,我们知道Activity的重建算是比较耗时的,会可能会有几百毫秒以上,那么这时候下载线程仍然在工作,进度肯定和保存时的进度不一致了,如何处理这个问题呢?

    第2个方案,大家可以自己展开思考,实际的项目中可能会需要额外做一些事情来处理ContentView的横竖布局的问题。

    如果使用Service来解决这个问题,看似是比较完美的,不过就会涉及Activity(UI)和Service的交互问题,这个我们以后再讨论。

    小结

    当我们知道了Service的用途,心中有一个Service相关的概念时,针对实际的场景还是要做具体的分析再决定是否使用Service。因为Service仍然是在主线程中调用,还是要开线程才能处理长时间的工作,Service和UI的交互也让这个方式变得不那么简便。如果你只需要在当前界面去做一些耗时操作,界面退出或改变时,工作也要停止,那么这时直接使用Thread(或者AsyncTask, ThreadHandler)会更合适你。

    Even 原创
    简书账号:Goeasyway
    简书链接:http://www.jianshu.com/users/f9fbc7a39b36/latest_articles
    转载请注明出处。
    对Android面试有兴趣的可以关注我的微信公众号:Android面试启示录

    Android面试启示录

    相关文章

      网友评论

      • IAM四十二:最后的ThreadHandler 应该是HandlerThread吧 :joy:
      • Mr_kvkk:不过service真的很少用...特别是现在service被厂商严重限制
        Mr_kvkk:@shushu516 因为安卓卡咯 每个app都在后台跑几个service 不卡都怪了
        shushu516:@Mr_kvkk 为何?控制功耗嘛
      • _孑孓_:我也很早接触Android开发,但是貌似水平跟年限不太匹配,糟心~~~
      • 大叔top:超级棒的文章 通过看第一行代码的总结 还有一些大神的文章 觉得受益匪浅 我要从第一章看起
      • dongbingliu:Service 定义:后台无界面

        Service 启动方式:
        StartService 、bindService

        区别:
        StartService 启动组件与Service无关联,组件销毁,Service可以继续存活,组件可以通过stopService 销毁service ,startService启动Service ,其生命周期为onCreate->onStartCommand->onDestroy

        bindService 启动组件与Service有通讯关联,组件销毁,组件也会自动销毁,取消关联unBind

        Service 中不能在onCreate中执行耗时操作,原因,Service在UI主线程中执行;

        Service中执行耗时操作方案:
        1. 开辟新的线程,Handle更新UI数据;
        2. 使用IntentService

        什么时候使用IntentService?
        1. 数据并发少的情况;

        转屏下载需求处理?
        1. 目前从事OTT开发,暂时没有处理过此问题
        望北8261:我也觉得转屏下载进度不需要处理,在Activity启动之后从Service中获取一下进度,而且进度会不断的传给Activity,根本不需要考虑保存进度
        CRL7885:总结的非常棒
      • PeterHe888:为什么多次启动同一个service只会产生一个实例呢?
        别说我有内涵哦:@PeterHe888 因为所有也得服务都缓存在一个hashmap中,不会重复创建
      • 水中_鱼:面试管都是流氓,
        goeasyway: @水中_鱼 😅
      • 一个疑问句:学习了
      • 206945be346a:使用aidl,activity启动一个远程service,实现activity和service的交互(接口),并尽量保证service在下载任务结束前不被kill,思考一下这样应该可以实现吧?
        goeasyway: @SundayPark 😜
      • 望北8261:MP3那个,可以用startService启动Service,然后用EventBus发送事件更新界面。

        用startService启动,然后在Activity中同时bindService进行数据交互也是可以,下载完毕stopSelf。

        “当启动方销毁时,Service也会自动进行unBind操作”,才知道这样,刚测了一下,确实这样,想想也应该这样
      • trycatchx:通过回调到activity 显示,把已下载的大小保存在service 里面的Thread 中。转屏后主动如果去获取一次。
        trycatchx:@监控都不 这个是必须的。可是注册监听不一定立马回调。这时候必须先 获取一次。不然进度条是0
        监控都不: @Overried 重新注册监听啊,你是不是傻
      • 朋友你的学生卡掉了:其实,IntentService的内部也是使用Handler来实现的,只不过对整个过程做了一些处理和封装。所以在一些简单的需求,就想作者说的只需要在当前界面去做一些耗时操作这样的需求时,直接使用Hnadler就好了。
      • zkxok:很好,我就要去面试了,先收下了😬
      • 不思则亡:保证下载进度的问题,是用回调接口来写么?
      • 那一年我两岁:写作风格很喜欢,内容很充实
      • 185ce2da4e57:service中弹出消息:toast和notification,还有前台service面试不问吗😂
      • 指尖流逝的青春:很好的总结,赞一个
      • Viking_Den:很有用,问题点很有价值,没有直接给出答案,值得自我思考
      • 7982ab8fd469:没有解读完整!!!
      • MigrationUK:转屏进度值放到onSaveInstanceState里?
        IM_RisingSun: @MigrationUK 并不合适,还是存在进度不一致的问题
      • 6e4f69559beb:楼主,第一个可不可以不缓存进度,直接计算下载到本地文件大小与源文件大小的比例,重新构建进度
      • 陶石子: :smiley: 谢谢楼主分享。
      • MigrationUK:很不错,很新颖的方式了解系列知识,感谢楼主
      • ButterKnife:楼主可以说说横竖屏切换时activity的生命周期的问题吗?我自己测试的和网上的文章不太一样,会不会是和api有关系?
        goeasyway:@ButterKnife 哪里不一样?
      • 09d8e043ac44:干货,谢谢楼主
      • 天青色等煙雨_而我在等妳:第1个方案就不需要处理contentView横竖布局的问题吗?
        goeasyway:@天青色等煙雨_而我在等妳 Activity onCreate时会得新建Layout
      • 天青色等煙雨_而我在等妳:针对第1个方案,我会继续问他将进度值存在哪里? 转屏的过程中,我们知道Activity的重建算是比较耗时的,会可能会有几百毫秒以上,那么这时候下载线程仍然在工作,进度肯定和保存时的进度不一致了,如何处理这个问题呢?

        存到Sharedpreference里就能实时更新进度了,或者存到Application一个成员变量里,也是可以的吧。
        IM_RisingSun: @天青色等煙雨_而我在等妳 楼主说的不是的存和取的效率问题,说的是你activity销毁的时候存储进度,但是下载服务还是一直在运行进度是一直变化的,等你activity重建好后进度早已变化很多了,而你读的还是老进度,明显不符合需求
        天青色等煙雨_而我在等妳:@goeasyway 相对于下载进度,这个存取时差应该是可以忽略吧?如果说文件读写时差较大,那么存到Application的一个成员变量里总可以吧?
        goeasyway:@天青色等煙雨_而我在等妳 要考虑时差,存和取之间是有时差的,这个时间差内下载线程并没有停止工作。
      • object_小车:关注,你的持续更新,学习ing
      • HaiChecker:Android快三年了,还有很多不了解,真心感谢。
      • 先森你的药:这个场景第一反应是使用retain fragment。
      • 工程师milter:具体是如何用service在activity重建后更新下载进度呢?AsyncTask中不是有一个参数专门发送处理进度吗,为什么service是更好的解决方案呢,请大神明示。
      • 墨螟:干货啊
      • yzytmac:楼主真大神也!我们是只知其然不知其所以然!支持楼主!以后多分享点干货
      • 胖胖欢:表示做android一年了,但是作者说的service问题最近在一次与其他应用交互中才第一次领略到,很有启发,谢谢
      • 橘子香蕉苹果:由工作进经验的人,看你的每一篇文章都会花费一些时间的,因为联想的比较多,作者也没有给出明确的答案,需要读者自己去思考、去联想、去验证,谢谢
        天青色等煙雨_而我在等妳:这系列文章真的很不错,激发了我不少思考。
        goeasyway:@wng2010 因为工作中也不可能什么事都是别人给欠按排好,还是需要自己动脑思考一下不同的方案。另,我也不希望大家是为了面试来背这个系列的文章,而是能思考一下怎么看待问题,怎么看待自己或别人。
      • 小胡闹:没项目经验,平常自己写点小东西,还真没用过service
      • HuDP:不错呀 赞一个 继续看下一篇
      • 84bf95ab9e56:会一直关注,多谢分享
      • AD小徐:面试时常常碰到像你这样的面试官,通常前面还能招架,后面越问越蒙……
        温瑜:@goeasyway 也是顺便看临场应变的调整?
        goeasyway:@小徐_ 其实也不会为难别人的,不会的话我们也会换话题的
        ee4d4a783be7:@小徐股缘 哈哈哈…爪握~
      • 68768b474bfc:期待Parcel专题
        goeasyway:@TellH 稍后写一篇
      • Mr_Yy:写的很棒,学习了
      • 68768b474bfc:实际开发还真很少用service,当初的service的入门知识都快忘光了
      • 李文文丶:@goeasyway 不会是发送广播来让前台更新ui吧,:joy::joy:
        info_gu:@李文文丶 我觉得那可以直接handler.post就可以更新进度了,主要是下载任务一般放在后台,所以要用服务,考的服务的知识
      • fuuuuuccccck:表示不知道IntentService。。。
        MiBoy:就是一个可以做耗时操作的service
        goeasyway:@fuuuuuccccck 可以直接看一下它的源代码,很短的:stuck_out_tongue_winking_eye:
      • 李文文丶:最后的场景,如果是面试我,我会这么说:activity用第一种方法启动一个服务,然后在这个服务里面使用handler下载网络数据,每秒获得一次进度条数值,然后通过服务发送广播给前台,前台进行每秒更新ui,可能是错的啊,我只是个大三的,不要打我
        8cd249b8ddf2:这种这么有界面针对性的需求,我觉得还是不要用广播比较好,我感觉广播用在一些全局事件监听比较妥,像什么低电量啊,断网啊,锁屏啊之类的。。。 这种后台音乐下载的,其实可以用第一个方法启动service,然后提权,变成前台进程(也就是会在通知栏显示进度),然后进度的变化通过eventBus来通知Activity,Activity destroy的时候就unRegister掉EventBus,用handler总要提防内存泄露的问题。@goeasyway 你觉得呢?
        goeasyway:@李文文丶 简书文章的第一个回复,所以我决定今天写广播的面试题来回答你的问题,请稍后关注。

      本文标题:Android面试一天一题(1 Day)

      本文链接:https://www.haomeiwen.com/subject/ebhvrttx.html