2019-04-26 一个关于Android启动页面的题目

背景

这个题目是最近面试 字节跳动(抖音)二面小哥提问的问题,但是由于紧脏和理解不够深刻导致没回答好,现在仔细分析一下这个题目。

题目

有四个Activity ,ABCD,他们的launchMode分别是standard,singleTop,singleTask,singleInstance,然后现在我们按照如下顺序打开:ABCDABCDAB,然后问退栈的时候的顺序。

解答

我们知道这四种模式除了standard,都有点说头,具体什么意思我也不多介绍,因为这都是基础,我们通过示意图和代码来解答这个问题。

这里我们建立了新的项目,然后配置好它们的启动模式。
然后我们在每个Activity中写同样的代码,如下:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d("TAG",getClass().getName() + "onCreate");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d("TAG",getClass().getName() + "onStart");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d("TAG",getClass().getName() + "onPause");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d("TAG",getClass().getName() + "onStop");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d("TAG",getClass().getName() + "onDestroy");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d("TAG",getClass().getName() + "onResume");
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Log.d("TAG",getClass().getName() + "onNewIntent");
    }
}

包括几个生命周期方法和onNewIntent方法的实现,我们给他打印执行。

当然我们要在A中添加启动B的按钮,B加启动C的按钮,以此类推。

运行起来,然后执行ABCDABCDAB,然后执行多次返回看log

//A 启动
cn.surine.bytedancequestion.MainActivityonCreate
cn.surine.bytedancequestion.MainActivityonStart
cn.surine.bytedancequestion.MainActivityonResume
//A中启动B
cn.surine.bytedancequestion.MainActivityonPause
cn.surine.bytedancequestion.SecondActivityonCreate
cn.surine.bytedancequestion.SecondActivityonStart
cn.surine.bytedancequestion.SecondActivityonResume
 cn.surine.bytedancequestion.MainActivityonStop
//B中启动C
cn.surine.bytedancequestion.SecondActivityonPause
cn.surine.bytedancequestion.ThirdActivityonCreate
cn.surine.bytedancequestion.ThirdActivityonStart
cn.surine.bytedancequestion.ThirdActivityonResume
cn.surine.bytedancequestion.SecondActivityonStop
//C中打开D
cn.surine.bytedancequestion.ThirdActivityonPause
cn.surine.bytedancequestion.FourthActivityonCreate
cn.surine.bytedancequestion.FourthActivityonStart
cn.surine.bytedancequestion.FourthActivityonResume
cn.surine.bytedancequestion.ThirdActivityonStop
//D中打开A
 cn.surine.bytedancequestion.FourthActivityonPause
cn.surine.bytedancequestion.MainActivityonCreate
cn.surine.bytedancequestion.MainActivityonStart
cn.surine.bytedancequestion.MainActivityonResume
cn.surine.bytedancequestion.FourthActivityonStop
//A中打开B
cn.surine.bytedancequestion.MainActivityonPause
cn.surine.bytedancequestion.SecondActivityonCreate
cn.surine.bytedancequestion.SecondActivityonStart
cn.surine.bytedancequestion.SecondActivityonResume
cn.surine.bytedancequestion.MainActivityonStop
//B中打开C,A先出栈然后B出栈【下面会分析这一块】
cn.surine.bytedancequestion.MainActivityonDestroy
cn.surine.bytedancequestion.SecondActivityonPause
cn.surine.bytedancequestion.ThirdActivityonNewIntent
cn.surine.bytedancequestion.ThirdActivityonStart
cn.surine.bytedancequestion.ThirdActivityonResume
 cn.surine.bytedancequestion.SecondActivityonStop
cn.surine.bytedancequestion.SecondActivityonDestroy
//C打开D (D实例还没销毁,单例系统只允许有一个D)
cn.surine.bytedancequestion.ThirdActivityonPause
cn.surine.bytedancequestion.FourthActivityonNewIntent
cn.surine.bytedancequestion.FourthActivityonStart
cn.surine.bytedancequestion.FourthActivityonResume
cn.surine.bytedancequestion.ThirdActivityonStop
//D打开A(新建A)
cn.surine.bytedancequestion.FourthActivityonPause
cn.surine.bytedancequestion.MainActivityonCreate
cn.surine.bytedancequestion.MainActivityonStart
cn.surine.bytedancequestion.MainActivityonResume
cn.surine.bytedancequestion.FourthActivityonStop
//A打开B (新建B)
cn.surine.bytedancequestion.MainActivityonPause
cn.surine.bytedancequestion.SecondActivityonCreate
cn.surine.bytedancequestion.SecondActivityonStart
cn.surine.bytedancequestion.SecondActivityonResume
cn.surine.bytedancequestion.MainActivityonStop
//返回开始,B出栈
cn.surine.bytedancequestion.SecondActivityonPause
cn.surine.bytedancequestion.MainActivityonStart
cn.surine.bytedancequestion.MainActivityonResume
cn.surine.bytedancequestion.SecondActivityonStop
cn.surine.bytedancequestion.SecondActivityonDestroy
//返回,A出栈
cn.surine.bytedancequestion.MainActivityonPause
cn.surine.bytedancequestion.ThirdActivityonStart
cn.surine.bytedancequestion.ThirdActivityonResume
cn.surine.bytedancequestion.MainActivityonStop
cn.surine.bytedancequestion.MainActivityonDestroy
//C出栈
cn.surine.bytedancequestion.ThirdActivityonPause
cn.surine.bytedancequestion.SecondActivityonStart
cn.surine.bytedancequestion.SecondActivityonResume
cn.surine.bytedancequestion.ThirdActivityonStop
cn.surine.bytedancequestion.ThirdActivityonDestroy
//B出栈
cn.surine.bytedancequestion.SecondActivityonPause
cn.surine.bytedancequestion.MainActivityonStart
cn.surine.bytedancequestion.MainActivityonResume
cn.surine.bytedancequestion.SecondActivityonStop
cn.surine.bytedancequestion.SecondActivityonDestroy
//A出栈
cn.surine.bytedancequestion.MainActivityonPause
cn.surine.bytedancequestion.FourthActivityonStart
 cn.surine.bytedancequestion.FourthActivityonResume
 cn.surine.bytedancequestion.MainActivityonStop
cn.surine.bytedancequestion.MainActivityonDestroy
//D出栈
cn.surine.bytedancequestion.FourthActivityonPause
cn.surine.bytedancequestion.FourthActivityonStop
cn.surine.bytedancequestion.FourthActivityonDestroy

额……这什么鬼玩意,好像打印东西太多了,我们挨着来看吧,边看边配图。

首先前面的好理解,分别是ABC进栈,然后上面的日志,我已经做好了分割。

打开A,B,C

然后我们启动D,由于D是singleInstance,于是我们单独开栈。


打开D

然后在D中打开A,然后B,示意图如下,可以参考日志。


打开AB

然后就是启动C,这里有几点看头,我们总结一下,首先我们知道C是singleTask,目前我们的C在栈中存在,所以我们会直接使用,但是使用的时候会将他头顶上的全部移除,如下。

A,B出栈

我之所以说上面的过程有看头是因为它的日志包含很多信息,我们copy这一段日志过来

//B中打开C,A先出栈然后B出栈【下面会分析这一块】
cn.surine.bytedancequestion.MainActivityonDestroy
cn.surine.bytedancequestion.SecondActivityonPause
cn.surine.bytedancequestion.ThirdActivityonNewIntent
cn.surine.bytedancequestion.ThirdActivityonStart
cn.surine.bytedancequestion.ThirdActivityonResume
 cn.surine.bytedancequestion.SecondActivityonStop
cn.surine.bytedancequestion.SecondActivityonDestroy

首先明确,由于A启动了B,A已经处于onStop阶段,然后B启动C的时候,优先执行了A的Destory方法,然后才是B的相关方法。

结合上面的示意图,很容易想到一个问题,是不是A执行onDestory的之后没有出栈,需要等B先出栈A才能出栈?
咨询了一下别人,他告诉我出入栈是由启动模式控制的,跟生命周期没有必然联系,不知道是不是这样的,具体我也不能确定,希望有明白的大神指点一二。

第二个问题,由于C是已经在栈中了,所以再找到它的时候执行的过程是onRestart过程,这里我没有复写这个方法,但是我们明显能看出onNewIntent方法是在onRestart过程期间执行的,这也能够给 onNewIntent调用时机 提供一个很好的解答。

然后我们继续看。


再次打开D

再次打开D的时候,由于D是singleInstance,系统中只能存在一个,所以复用,也调用了onNewIntent方法。

然后新建A,B


新建A,B

然后出栈顺序就是BACBAD ,上面的日志也已经印证了这个过程。

注意D这个栈是单独的,所以要等主栈出完才能出,所以不要联想别的支付场景啊,什么什么的,只需要按部就班的分析栈内活动即可。

总结

这个题目就是基础题目,奈何可能掌握不周到,加上紧张就回答错了,时隔多天,再次整理并且做了实验,以后对于此类题目就得心应手了。

你可能感兴趣的:(2019-04-26 一个关于Android启动页面的题目)