Android 启动模式及singleTask与Home键存在的问题

版权声明:本文为博主csdn_aiyang原创文章,未经博主允许不得转载。 https://blog.csdn.net/csdn_aiyang/article/details/88692180

目录

一、前言

二、查看Log日志过程

三、问题分析(标红要注意)

四、原理分析

五、解决方式


一、前言

在项目设计中,经常用到点击“退出”,需要清除掉所有Activity,跳转到登录页面。所有采用Android的启动模式。

  • standard 标准模式,也是activity的默认启动模式。在这种模式下activity可以被多次实例化,即在同一个栈中可以存在多个activity的实例,每个实例都会处理一个Intent对象。
  • singleTop 栈顶模式。该模式与standard模式一样Activity可以被多次实例化,唯一区别在于:若栈顶已经存在该Activity实例,Intent不会再创建一个Activity,而是调用onNewIntent()方法。
  • singleTask 栈内模式。该模式的Activity只允许在系统中拥有一个实例。如果系统中已经有了一个实例,这个实例将移动到栈顶,同时清掉之前它上面的其他Activity。如果没有,则会创建一个新的Activity并置放在合适的任务中。
  • singleInstance 单例模式。该模式非常接近于singleTask,系统中只允许一个Activity的实例存在。区别在于:该Activity存在于独立的栈中。

很明显,在登录页面设置为SingleTask模式最合适。代码如下:

    <activity
            android:name=".ui.activity.LoginActivity"
            android:launchMode="singleTask">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
     </activity>

     <activity android:name=".ui.activity.MainActivity" />

 但是,测试人员说发现bug:

1、登录成功进入MainActivity页面,然后点击Home键回到桌面,再次点击应用图标,竟然回到LoginActivity页面。

2、在LoginActivity页面点击返回键回到桌面,再次点击应用图标,竟然回到LoginActivity页面。

案情回顾:

( 图片有点晃眼!!!为了避免影响专心看下面的讲解,我们留白

留白

留白

留白

留白

把图片移上去)

二、查看Log日志过程

打开登录页面:

//打开登录页面
03-20 17:07:00.445 31284-31284/com.yum.restaurant D/SingTask:: onCreate
03-20 17:07:00.450 31284-31284/com.yum.restaurant D/SingTask:: onStart
03-20 17:07:00.453 31284-31284/com.yum.restaurant D/SingTask:: onResume

跳转到主页:

03-20 17:08:00.092 31284-31284/com.yum.restaurant D/SingTask:: onPause
03-20 17:08:00.295 31284-31284/com.yum.restaurant D/SingTask:: onCreate
03-20 17:08:00.299 31284-31284/com.yum.restaurant D/SingTask:: onStart
03-20 17:08:00.301 31284-31284/com.yum.restaurant D/SingTask:: onResume
03-20 17:08:00.915 31284-31284/com.yum.restaurant D/SingTask:: onStop

在主页,点击Home键回桌面:(重点)


03-20 17:09:27.753 31284-31284/com.yum.restaurant D/SingTask:: onPause
03-20 17:09:28.289 31284-31284/com.yum.restaurant D/SingTask:: onStop

点击应用图标:(重点)

//点击应用图标,回到了登录页面
03-20 17:10:39.087 31284-31284/com.yum.restaurant D/SingTask:: onDestroy(MainActivity)
03-20 17:10:39.100 31284-31284/com.yum.restaurant D/SingTask:: onNewIntent(LoginActivity)
03-20 17:10:39.114 31284-31284/com.yum.restaurant D/SingTask:: onStart
03-20 17:10:39.128 31284-31284/com.yum.restaurant D/SingTask:: onResume

在登录页面,按返回键:

//登录页面,按返回键
03-20 17:11:41.050 31284-31284/com.yum.restaurant D/SingTask:: onPause(LoginActivity)
03-20 17:11:41.604 31284-31284/com.yum.restaurant D/SingTask:: onStop
03-20 17:11:41.606 31284-31284/com.yum.restaurant D/SingTask:: onDestroy

再次,点击应用图标:

//重新启动LoginActivity
03-20 17:13:31.021 31284-31284/com.yum.restaurant D/SingTask:: onCreate
03-20 17:13:31.025 31284-31284/com.yum.restaurant D/SingTask:: onStart
03-20 17:13:31.026 31284-31284/com.yum.restaurant D/SingTask:: onResume

三、问题分析(标红要注意)

通过上面的日志,可以发现一个非常重要的可疑点:当在标准启动模式下点击home键,会走onPause、onStop生命周期,点击应用图标时清除SingTask模式上的其他Activity,并调用了onNewIntent()方法。   

这就是Android的singleTask设计的独特之处。没办法,人家就是这么设计的,很强硬。下面从原理寻找解决方法。

四、原理分析

Task(任务)是Android Framework中的一个概念,Task是由一系列相关的Activity组成的,是一组相关Activity的集合,以栈(Stack)的形式来管理的。在启动模式为standard或singleTop时,一般是在同一个任务中对Activity进行调度,而在启动模式为singleTask或singleInstance是,一般会对Task任务进行整体调度,其中包括:在Launcher或HomeScreen点击app图标,会开启一个新任务或者是将已有的任务调度到前台。

另外,我们知道,如果一个Activity设置了"singleTask"启动模式,再次创建这个Activity实例时会先查看任务栈是否已经存在相应的Activity实例,如果存在,就会把位于这个Activity实例上面的Activity全部Destroy掉,使这个Activity实例置于Stack栈顶端。

最后,singleTask的模式有个FLAG_ACTIVITY_BROUGHT_TO_FRONT。官方文档上的解释如下:

    If, when starting the activity, there is already a task running that starts with this activity, then instead of starting a new instance the current task is brought to the front. The existing instance will receive a call to Activity.onNewIntent() with the new Intent that is being started, and with the Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT flag set. This is a superset of the singleTop mode, where if there is already an instance of the activity being started at the top of the stack, it will receive the Intent as described there (without the FLAG_ACTIVITY_BROUGHT_TO_FRONT flag set). See the Tasks and Back Stack document for more details about tasks.

    大意:当启动一个activity的时候,如果这个task中有这个activity的实例,这个实例就会被放到当前的task的前面,这个存在的实例是通过onNewIntent()调用实现的,伴随着这个activity的flag(FLAG_ACTIVITY_BROUGHT_TO_FRONT )会被设置,这是singleTop模式的父集,如果当这儿已经有个实例的activity在这个栈的顶部,这时候它不会设置这个flag(FLAG_ACTIVITY_BROUGHT_TO_FRONT )的值,详解看tasks和栈说明,更清楚的了解这方面的知识!


五、解决方式

通过一个标准Standard模式的Activity去启动SingleTask的Activity,就可以避免这个问题。

这里我设计的是从闪屏页SplashActivity跳转到LoginActivity页面。

参考链接:

https://blog.csdn.net/qq_16318981/article/details/52290043 

https://blog.csdn.net/a1031359915/article/details/42212919

猜你喜欢

转载自blog.csdn.net/csdn_aiyang/article/details/88692180