美文网首页Android潜修者面试题Android 开发经验集
Android面试一天一题(Day 20:程序员何苦为难程序员(

Android面试一天一题(Day 20:程序员何苦为难程序员(

作者: goeasyway | 来源:发表于2016-07-27 21:27 被阅读4959次

    大大咧咧的东北人Timothy和我在两个公司都做过同事,虽然同为程序员,但Timothy一直在沟通和应酬方面展示出他强于一般程序员的能力。2013年的时候,他选择辞职跨界到菲律宾的马尼拉卖光盘,就是那种用来刻录的空白光盘,虽然我们很少使用了,但在东南亚还很有市场。一个月大概能卖出一两百万张光盘,这么几年下来不知道卖出去的光盘连起来能不能绕地球一圈?

    今天问了一下Timothy不当程序员的感受,“做程序员太累了,主要也是自己不喜欢编程,现在自由多了。”Timothy在程序员35岁坎之前解决了他的问题,直接由程序员转做Boss了。

    当问他还对以前面试Android工作时被问到的问题有印象吗?Timothy能想起来的也就是这一道“程序员何苦为难程序员”的Activity启动模式相关的问题。

    面试题: Activity的启动模式有哪些,有什么区别?

    要理解Activity的四种启动模式,我们得来先说说Activity任务和返回栈的事。强烈建议大家可以先读一下官方的文档Tasks and Back Stack,官方已经翻译成中文了,不存在阅读障碍(有可能需要代理或者VPN才能登录此网站)。

    简单说,Task是为了完成某个工作的一组相关联的Activity的集合。这些Activity可以来自不同的APK(即可以在不同的进程),为了方便大家更直观感受一下,可以使用adb命令查看一下当前运行的Task:

    adb shell dumpsys activity activities

    注意其中的几个关键字:

    Stack
    TaskRecord
    ActivityRecord

    用图形来表示如下:



    "Hist"代表Task中的ActivityRecord,可以理解成对应某个实际的Activity。
    "Stack #0"表示mHomeStack(ActivityStack类),保存了Launcher相关的Activity的Task。
    "Stack #1"表示mFocusStack(ActivityStack类),用于保存Launcher除外的其他应用的Activity组成的Task。

    这两个Stack由ActivityStackSupervisor负责组织管理,在Android 4.4之前的版本是没有ActivityStackSupervisor这个类的,也没有"Stack #"的划分,AMS直接管理Task的列表。

    Android也提供了ActivityManger.getRunningTasks()的接口,可以在得到RunningTaskInfo的列表(当前Android设备正在运行着的Task)。从RunningTaskInfo中又可以进一步得到更多的相关信息。

    四种启动模式

    理解了这些相关的结构,我们再来看四种启动模式就简单多了,说白了这些启动模式就是设置Activity如何被组织到相关的任务栈中。从字面上也很好解释每种模式的意思。

    在配置Activity的属性时设置android:launchMode,有如下四种模式供选择:
    standard
    singleTop
    singleTask
    singleInstance

    正如文档Tasks and Back Stack也提到的,我们还要注意下面这几个Intent标签的用法:

    FLAG_ACTIVITY_NEW_TASK
    FLAG_ACTIVITY_CLEAR_TOP
    FLAG_ACTIVITY_SINGLE_TOP

    如我常会问面试者一个问题:

    当前应用有两个Activity A和B,B的android:launchMode设置了singleTask模式,A是默认的standard,那么A startActivity启动B,B会新启一个Task吗?如果不会,那么startActivity的Intent加上FLAG_ACTIVITY_NEW_TASK这个参数会不会呢?

    如果认真阅读了Tasks and Back Stack文档的“处理关联”这个章节的话,应该能回答这个问题。关联(taskAffinity)也是Activity的一个属性,默认值是应用的包名。

    设置了"singleTask"启动模式的Activity,它在启动的时候,会先在系统中查找属性值affinity等于它的属性值taskAffinity的任务存在;如果存在这样的任务,它就会在这个任务中启动,否则就会在新任务中启动。

    当Intent对象包含FLAG_ACTIVITY_NEW_TASK标记时,系统在查代时仍然按Activity的taskAffinity属性进行匹配,如果找到一个Task的taskAffinity与之相同,就将目标Activity压入此Task栈中,如果找不到则创建一个新的Task。

    注意:设置了"singleTask"启动模式的Activity在已有的任务中已经存在相应的Activity实例,再启动它时会把这个Activity实例上面的Activity全部结束掉。

    因为这几种模式在面试题中太过出名了,但实际上真正理解和使用过的人并不多,往往用如下的问题就很容易区分出来:

    1. 设置为singleTask的启动模式,当Activity的实例已经存在时,再启动它,它的那么回调函数会被执行?我们可以在哪个回调中处理新的Intent协带的参数?(通过startActivity(Intent)启动)
    1. 或者问设置为singleTop的启动模式,当Activity的实例已经存在于Task的栈顶,我们可以在哪个回调中处理新的Intent协带的参数?(在当前Activity中从通知栏点击再跳转到此Activity就是这种在栈顶的情况)

    这两个问题就是想看看面试者是否真正的做过这样的设置,或者是否知道有onNewIntent这个回调函数的存在。

    引申

    上面提到了通知栏,那么再说一个场景,在项目中常遇到一个需求就是在通知栏中使用PendingIntent跳转到相关的Activity。但这个Activity往往是根据通知的内容的具体的Activity,通知来的时候有可能应用已经被KILL掉了,这时跳转这个具体内容的DetailActivity后,我们希望按Back键能回退到应用的主界面(MailActivity),你会怎么做呢?

    在DetailActivity中onBackPressed做判断?

    如果没有很好的解决方案的话,大家可以看看:TaskStackBuilder。

    小结

    希望这两篇文章没有“为难”到各位,不过我想大家以后遇到Activity跳转和栈管理的问题时会优先想到启动模式和Intent可协带的Flag,通过一定的组合就可以轻松的解决的实际的问题。至于各种奇葩的问题,那就具体问题再具体分析,至少你知道了这些相关的概念查找分析问题也会事半功倍。

    关于程序员的“35岁坎”(业界就是这样流传的),我们都需要各自好好思考一下。如果一样东西我们学过、使用过,但当我们不在这个行业时,这个当年费尽辛苦学来的东西还能记住什么呢?会不会也只是很少的一部份,只是当年让我们为难的痛点呢?当有一天Android被淘汰了,或者自己转行了,那么从Android这个平台上我们学习到了什么呢?什么是会变的,什么又是不变的呢?

    我想不变的东西,才是值得我们仔细思考的。

    Even 原创
    简书账号:Goeasyway
    简书链接:http://www.jianshu.com/users/f9fbc7a39b36/latest_articles
    转载请注明出处。

    相关文章

      网友评论

      • yask:mianactivity做路由
      • BobEve:关于这一点,我之前处理是直接跳转MainActivity,然后通过路由分析再跳转到对应的Activity中,App内已经设置了路由和相关的处理规则,如业务、type相关跳转。
        不好地方是如果有新路由规则需要进行更新,但是大部分情况还是适应的。
        请问@goeasyway 这样的处理方式是否可行,是否有更好的处理方式?
        望北8261::joy: 我现在项目就有这个需求,我就是这么做的,暂时没发现什么问题
        BobEve:哈哈,我这属于挖坟贴么,应该不算吧 离最后一条评论还没过一年呢 ~~!
      • 俗气的我:十分赞同『我想不变的东西,才是值得我们仔细思考的』这句话。之前一直认为『变化是永恒的』,但我现在开始觉得『在特定的时间和环境下,不变才是永恒的』,特别是在编程中,我们永远都无法跟上变化的脚步,只有抓住不变,才能适应变化。
      • 9b4f2400ea72:FLAG_ACTIVITY_NEW_TASK
        在新任务中启动 Activity。如果已为正在启动的 Activity 运行任务,则该任务会转到前台并恢复其最后状态,同时 Activity 会在 onNewIntent() 中收到新 Intent。
        正如前文所述,这会产生与 "singleTask"launchMode 值相同的行为。

        这是官网的描述。

        但是我在4.4的天天模拟器上面实测发现FLAG_ACTIVITY_NEW_TASK并不像singleTask弹出任务栈之上的activity。而是像standard一样创建一个新的放在任务栈上面。
        Jdqm:@中二菜鸡 再加一个ckearTop
        9b4f2400ea72:这个FLAG_ACTIVITY_NEW_TASK到底有什么用处呀。。。
      • sufun_wu:不变的东西,才是要考虑的。现在的变化太快了,博主说得好
      • trycatchx:最后一个问题,1.复写back 直接跳转到MailActivity,当然要和正常流程的点击back 区分开。2.好像可以强行把maiActivity 手动压入栈,那么就不用复写back 。补充:MailActivity 必须是singtask
        陆仁丙:@TonyEasy 可以的,感觉是一种比较友好的解决方式👍
        trycatchx:@TonyEasy 没有错!以前写你这一种的时候看了一下 API level >= 11,现在手机基本都支持了!(以前那年代 还要兼容2.3, API= 9):smile:
        TonyEasy:同时启动两个Activity,一个是MainActivity,一个是DetailActivity,首先MainActivity是singleTask启动模式;
        Intent[] intents = new Intent[2];
        intents[0] = Intent.makeRestartActivityTask(new ComponentName(context, MainActivity.class));
        intents[1] = resultIntent;
        PendingIntent.getActivities(context, id, intents, PendingIntent.FLAG_UPDATE_CURRENT);
      • x耶律:很喜欢楼主写的文章,最近在面试被一个面试官问道activityA跳转到activityB走的生命周期方法。我的回答是A:Onpause->B:Oncreate->Onstart->OnResume->A:Onstop
        然后我说在系统内存紧张的时候可能A的Onstop不会走就被回收掉了,但是这个面试官说在Android3.0之后Activity的Onstop方法一定会走,说我这个说法不对。请问确实有这个说法吗
        耿木:Be aware that these semantics will change slightly between applications targeting platforms starting with HONEYCOMB vs. those targeting prior platforms. Starting with Honeycomb, an application is not in the killable state until its onStop() has returned. This impacts when onSaveInstanceState(Bundle) may be called (it may be safely called after onPause() and allows and application to safely wait until onStop() to save persistent state.
      • 8cd249b8ddf2:关于singleTask这个,如果A activity是standard,B activity是singleTask,A启动B的时候,如果B没有指定taskAffinity,B还是会和A在同一个任务里面吧?
        1417a57a5af2:@Beary 会在同一个Task中
      • chonrp27512:TaskStackBuilder这个方法在vivo手机上获取不到parentactivityName,会为空,导致返回的时候直接退出应用,别的手机是正常的,我想看vivo的源码,查找为什么,但似乎找不到源码可以查证。
        chonrp27512:嗯,在vivox5pro上,我循环遍历了activity信息,这个字段是空的。在其他手机上是有值的。博主可以看下有没有这个测试机测试下。
        goeasyway:@chonrp27512 只有这个属性取不到?
      • Sunning:mark
      • BeWinner:希望继续
      • doulala:很认可最后一段总结
      • 工程师milter:表示读过Ian Lake 的《UP AND BACK》博文后,此类题目轻松拿下
        工程师milter:@milter 在medium网站上搜文章名可得
        e22f668396cf:@milter 有链接吗?
      • 乆丩乣::smiley:
        NextGame:@乆_丩 总结的相当到位啊

      本文标题:Android面试一天一题(Day 20:程序员何苦为难程序员(

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