今天分享一波面试系列,都是一些面试时肯定会被问到的问题,其中的内容也是和我被面试的实际情况息息相关,希望能帮大家踩一点坑。
说说Android的四种启动模式
这基本是一道必考题,和「Activity的生命周期」一样,基本为必考题。
其实很多人可能存在一个误区,觉得知道这个启动模式「launchMode」没什么意义,但我在毫无准备的前提下,被问到这个问题的时候,我被问的瑟瑟发抖。
这些都是基本
先普及下可能大多数人都知道的基本见解。
这是Activity的默认启动模式,每次激活Activity的时候都会创建一个新的Activity实例,并放入任务栈中。使用场景:基本绝大多数地方都可以用。
这可能也是非常常用的launchMode了。如果在任务的栈顶正好存有该Activity的实例,则会通过调用onNewIntent()方法进行重用,否则就会同standard模式一样,创建新的实例并放入栈顶。即便栈中已经存在了该Activity的实例,也会创建新的实例,即:A->B->A,此时栈内为A->B->A,但A->B->B,此时栈内为A->B。一句话概述就是:当且仅当启动的Activity和上一个Activity一致的时候才会通过调用onNewIntent()方法重用Activity。使用场景:资讯阅读类APP的内容界面。
这个launchMode专门用于解决上面singleTop的另外一种情况,只要栈中已经存在了该Activity的实例,就会直接调用onNewIntent()方法来实现重用实例。重用时,直接让该Activity的实例回到栈顶,并且移除之前它上面的所有Activity实例。如果栈中不存在这样的实例,则和standard模式相同。即:A->B->C->D->B,此时栈内变成了A->B。而A->B->C,栈内还是A->B->C。使用场景:浏览器的主页面,或者大部分APP的主页面。
在一个新栈中创建该Activity的实例,并让多个应用共享该栈中的该Activity实例。一旦该模式的Activity实例已经存在于某个栈中,任何应用再激活该Activity时都会重用该栈中的实例,是的,依然是调用onNewIntent()方法。其效果相当于多个应用共享一个应用,不管是谁激活,该Activity都会进入同一个应用中。但值得引起注意的是:singleInstance不要用于中间页面,如果用户中间页面,跳转会出现很难受的问题。这个在实际开发中我暂未遇到过,不过Android系统的来电页面,多次来电均是使用的同一个Activity。
四种模式的背书式理解记忆讲完了,你认为这样就结束了吗?
对,我也一度是这样认为的。
再说说我们的Intent标签
我们除了需要知道在AndroidManifest.xml里面设置android:launchMode属性,我们还需要了解下面这几个Intent标签的用法。
我们当然可以选择看看官方文档TasksandBackStack(你可能需要梯子)。
在Android中,我们除了在清单文件AndroidManifest.xml中配置launchMode,当然可以用Intent标签说事儿。启动Activity,我们需要传递一个Intent,完全可以通过设置Intent.setFlags(intflags)来设置启动的Activity的启动模式。
需要注意的是:通过代码来设置Activity的启动模式的方式,优先级比清单文件设置更高。
这个标识会使新启动的Activity独立创建一个Task。
这个标识会使新启动的Activity检查是否存在于Task中,如果存在则清除其之上的Activity,使它获得焦点,并不重新实例化一个Activity,一般结合FLAG_ACTIVITY_NEW_TASK一起使用。
等同于在launcherMode属性设置为singleTop。
前面讲了这么多,似乎相当全面了,但你以为这样就结束了?No,面试官一般情况下已经不会这么问你了,这样问你完全可以背出来。
面试官怎么问Activity的启动模式(launchMode)?
怎么问?
1、设置为singleTask的启动模式,当Activity的实例已经存在时,再启动它,它的哪个回调函数会被执行?我们可以在哪个回调中处理新的Intent协带的参数?(通过startActivity(Intent)方式启动)
2、设置为singleTop的启动模式,当Activity的实例已经存在于Task的栈顶,我们可以在哪个回调中处理新的Intent协带的参数?(在当前Activity中从通知栏点击再跳转到此Activity就是这种在栈顶的情况)
这两个问题如果你看了上面的,一定对你来说实在太简单了。面试官只是想直接考察你是否真正做过这样的设置,或者是否知道onNewIntent()这个方法的存在。
有没有其他想说的?
有。
之前在一篇文章中看到过这样一种情况,发现之前同事写的代码导致了这样一个问题。
startActivityForResult启动一个Activity,还没有开始界面跳转,直接就执行了onActivityResult()。
不知道有没有人也遇到过这样的问题,但我想遇到这个问题的时候,你一样会因此而抓耳挠腮。(可能是因为我们一般在排查问题的时候,很少去关注配置清单文件AndroidManifests.xml。)
我们在Activity.java的startActivityForResult()方法中可以看到这样一串说明。
很多人出现这个问题,确实是因为startActivityForResult()启动的Activity设置了singleTask的启动模式。
好在Android5.0以后,修正了这个问题。不过当你在Intent中设置FLAG_ACTIVITY_NEW_TASK后还是会出现这样的问题。
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
注意:MainActivity的onResume()也会被触发。因为onActivityResult()被执行时,它会重新获得焦点。很多人也会遇到onResume()被无故调用,也许就是这种情况。
所以,最终我们发现只要是不和原来的Activity在同一个Task就会产生这种立即执行onActivityResult()的情况,从原代码也可以得到验证,详情查看ActivityStackSupervisor.java。
小结
关于Activity的启动模式相关的问题,其实还会有很多种考察你掌握情况的问法,建议采用STAR法则进行面试回答。其实只要你掌握了实质,后面的运用只看你个人的运用能力和创新了。
最后
不用多说,相信大家都有一个共识:无论什么行业,最牛逼的人肯定是站在金字塔端的人。所以,想做一个牛逼的程序员,那么就要让自己站的更高,成为技术大牛并不是一朝一夕的事情,需要时间的沉淀和技术的积累。
关于这一点,在我当时确立好Android方向时,就已经开始梳理自己的成长路线了,包括技术要怎么系统地去学习,都列得非常详细。