Activity singleInstance启动模式

简介:

Android singleInstance启动模式实际开发中使用频率不高,最近解了一个bug,与此相关,bug虽然很轻松的解决了,但由它引发的对Activity的启动模式的思考却有点意思,本篇记录分享下。

引出问题的bug

  • 问题描述:Actvity-A启动了一个新的Actvity-B,Actvity-B嵌入了一个Fragment,Actvity-A和Actvity-B都属于同一个应用。此时连续按两次recent键重回Actvity-B,点击back键直接退出到桌面,而预期的结果应该是返回Actvity-A。整个过程示意图如下(Ubuntu暂时未找到好的录制GIF软件,主要领会过程^_^): 
    这里写图片描述
  • 问题分析:首先怀疑点击back键后应用在后台发生了Crash,因fragmewrok层做了异常拦截,此时不会有crash弹框出来,应用直接异常退出了,根据测试提供的log,未发现异常log,此种情况排除。接着排查Fragment及其所依附的Actvity-B的主要生命周期方法,看是否存在逻辑错误,也未发现明显异常。这个时候就怀疑是使用了错误的启动模式导致问题,果然在Manifest清单文件里发现Activity-B配置了android:launchMode=”singleInstance”,Actvity-B就是一个设置应用的界面,没必要设置成singleInstance,于是删除该行问题得到解决。
  • 问题延伸:bug虽然解决了,但却引起了1个疑问: 
    为何设置成singleInstance就会出现这种bug

Task 与 Back Stack

要弄清上面的问题,不得不先提下Tasks和Back Stack的概念。 
Android系统下,当用户为了完成某一个功能可能需要进行多个Actvitiy间的跳转才能达到目的,这些Activity的跳转序列就被Android抽象成了一个Task。而这一组Actvitiy实例都被放到了同一个栈中,先启动的Activity位于栈底,最后到达的Activity位于栈顶。一般而言Task的启动点都是从home 界面算起,点击Launcher界面的应用icon,如果之前没有启动过,则系统新建一个Task,刚启动应用的主Activiy被压入栈底,栈内的Activity是不会在内部重新排列的,只能按先入后出的顺序呈现,当用户连续按back键,使得栈底的Activity也pop出栈,栈为空了,这时该Task结束。Task是抽象的概念,指带了一组Activity,它们为实现用户的某个操作目的而聚在了一起,可以来自不同应用,Back Stack是实实在在用来存放管理这一组Activity的。Back Stack可以放多个Task,而每一个Task可以包含一个或多个Activity实例。 
当用户操作同一个Task内的Activity时,其默认的情况如下: 
- Activity-A启动Activity-B后,Activiyt-B被压入Activity-A所处的栈中并位于其上, Activity-A不在可见,但状态被记录下来,比如Activity-A里面EditText内输入的内容,当用户按一次back键返回时Activity-A重新可见,并且其内部的EditText输入内容依然存在,Activiyt-B被pop出栈,状态不保留。
- Activity-A启动Activity-B后,用户按home键返回桌面,系统会将此时的task打包进行状态保存,也就是说位于栈内的每个Activity状态都被保存下来了。用户重新启动激活该task,位于栈顶的Activity 可见并走onResume方法。

还原Bug对应的Task现场

写一个demo还原当时的Task现场。代码很简略,目的就是实验singleInstance启动模式对back键的影响。 
ActivityA代码:

package com.azhengye.demolaunchmode;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View; import android.view.View.OnClickListener; public class ActivityA extends Activity implements OnClickListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_a); findViewById(R.id.start_b).setOnClickListener(this); } @Override public void onClick(View v) { Intent intent = new Intent(ActivityA.this, ActivityB.class); startActivity(intent); } } 
  • 24

ActivityB代码:

package com.azhengye.demolaunchmode;

import android.app.Activity;
import android.os.Bundle;

public class ActivityB extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_b); } }

 

清单代码:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.azhengye.demolaunchmode" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="22" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".ActivityA" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".ActivityB" android:launchMode="singleInstance" /> </application> </manifest>
  • 1
  • 2

布局文件省略掉,注意这里在清单文件中对ActivityB的启动模式做了设置android:launchMode="singleInstance"。启动demo程序,从ActivityA跳转到ActivityB,此时停留在ActivityB,使用命令: 
adb shell dumpsys activity a 
查看当前的任务栈信息。demo中的信息输出如下图,为了方便呈现,只保留了部分输出。 
这里写图片描述
然后我们将清单文件中的android:launchMode="singleInstance"去掉,输出如下: 
这里写图片描述

对照上面的有下面的结论: 
1. 当设置了singleInstance启动模式,ActivityA和ActivityB都被放到了同一个栈中,即Stack #41,但是它们分属不同的Task,ActivityA位于Task344,ActivityB位于Task435。 
2. 默认的启动模式,ActivityA和ActivityB都被放置在了同一个Task中。 
3. 任务栈其实包含了两个概念–栈和任务(Task),一个栈里可以有多个任务(Task),一个任务(Task)可以有多个Activity。

结论

开篇提出的问题”为何设置成singleInstance就会出现这种bug?”这里我是这样理解的:前台Activity所属的task清空就会返回到桌面,因为singleInstance模式启动的Activity会新开一个独立的task,当按下back键后,该task中的唯一ActivityB 被pop出栈,Task为空,直接返回了桌面。




    本文转自 一点点征服   博客园博客,原文链接:http://www.cnblogs.com/ldq2016/p/6956800.html,如需转载请自行联系原作者


相关文章
|
Shell Android开发 容器
你真了解Android任务栈 Task 与启动模式吗?
你真了解Android任务栈 Task 与启动模式吗?
132 0
|
存储 Android开发
Activity的启动模式和启动流程
标准模式(standard) 栈顶复用模式(singleTop) 栈内复用模式(singleTask) 单例模式(singleInstance) 启动模式可在AndroidManifest.xml中,通过<activity>标签的android:launchMode属性设置。
|
Java Android开发
Activity的四种启动模式
Android的冷门知识,大家有兴趣可以了解了解
193 0
|
Android开发 容器
Android Activity的启动模式
关于activity的启动模式,相信但凡有点android开发基础的人都知道,但是为什么还要说呢,主要还是容易忘记,基础的东西更加容易让人忘记,而且我最近看了一本书,关于activity的启动模式的,虽然书中的内容跟我平时对activity启动模式的理解是一样的,但是比较详细,容易懂,在这里记录一下。
124 0
|
Android开发
Activity四种启动模式
Activity四种启动模式
|
Android开发 数据格式 XML
Activity的启动模式
任务栈 android任务栈又称为Task,它是一个栈结构,具有后进先出的特性,用于存放我们的Activity组件。 我们每次打开一个新的Activity或者退出当前Activity都会在一个称为任务栈的结构中添加或者减少一个Activity组件,因此一个任务栈包含了一个activity的集合, android系统可以通过Task有序地管理每个activity,并决定哪个Activity与用户进行交互:只有在任务栈栈顶的activity才可以跟用户进行交互。
1108 0
|
Android开发
理解Activity的启动模式
Activity的启动模式有哪几种,分别用于什么场景? standard:标准模式 系统的默认模式。一种典型的多实例实现。每次启动一个Activity都会重新创建一个新的实例。
1065 0
|
Web App开发 Android开发
|
Web App开发 JavaScript 前端开发