Android开发学习教程(24)- Android中Activity的启动模式(LaunchMode)和使用场景

0 652

1、为何须要启动模式
在Android开发中,咱们都知道,在默认的状况下,若是咱们启动的是同一个Activity的话,系统会建立多个实例并把它们一一放入任务栈中。当咱们点击返回(back)键,这些Activity实例又将从任务栈中一一移除,遵循的原则是“后进先出”(先进后出)。android

这里咱们考虑一个问题,当咱们屡次启动同一个Activity,系统也会建立多个实例放入任务栈中,这样岂不是很耗费内存资源?为了解决这一问题,Android为Actiivty提供了启动模式。shell

Activity的启动模式有四种:standard、singleTop、singleTask和singleInstance。app

2、启动模式的分类
一、standard:标准模式
这种启动模式为标准模式,也是默认模式。每当咱们启动一个Activity,系统就会相应的建立一个实例,无论这个实例是否已经存在。这种模式,一个栈中能够有多个实例,每一个实例也都有本身的任务栈。并且是谁启动了此Activity,那么这个Activity就运行在启动它的Activity所在的栈中。ide

Manifest中配置:
对于标准模式,android:launchMode=”standard”能够不写,由于默认就是standard模式。
<activity
android:name=".StandardActivity"
android:launchMode="standard" >
</activity>

测试

使用案例:
MainActivity有一个按钮,点击按钮会打开StandardActivity。打开StandardActivity也有一个按钮,点击也是启动一个StandardActivity。而且咱们在onCreate()方法中打印TaskId和hashCode值。
打开步骤:MainActivity->StandardActivity->StandardActivity->StandardActivitythis

MainActivity:对象

public class MainActivity extends AppCompatActivity {内存

private static final String TAG = MainActivity.class.getSimpleName();资源

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_demo);开发

findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
StandardActivity.open(MainActivity.this);
}
});

Log.e(TAG, "———onCreate(): TaskId: " + getTaskId() +", hashCode: " + hashCode());

}

}

StandardActivity :

/**
* 启动模式:Standard(标准模式)
*/

public class StandardActivity extends AppCompatActivity {

private static final String TAG = StandardActivity.class.getSimpleName();

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launch_mode);

findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
open(StandardActivity.this);
}
});

Log.e(TAG, "———onCreate(): TaskId: " + getTaskId() +", hashCode: " + hashCode());
}

public static void open(Context context) {
context.startActivity(new Intent(context, StandardActivity.class));
}

}

控制台打印log以下:

经过案例的log分析,能够得出标准模式下,每当打开一次Activity就会建立一个新的实例,由于hashCode值都不一样,并且都建立在启动它的Activity所属的任务栈中,也就是MainActivity所在的任务栈中,由于它们的任务栈Id一致。

分析总结:
标准模式下,只要启动一次Activity,系统就会在当前任务栈新建一个实例。

使用场景
正常的去打开一个新的页面,这种启动模式使用最多,最普通 。

二、singleTop:栈顶复用模式
这种启动模式下,若是要启动的Activity已经处于栈的顶部,那么此时系统不会建立新的实例,而是直接打开此页面,同时它的onNewIntent()方法会被执行,咱们能够经过Intent进行传值,并且它的onCreate(),onStart()方法不会被调用,由于它并无发生任何变化。

Manifest中配置:
<activity
android:name=".SingleTopActivity"
android:launchMode="singleTop">
</activity>
1
2
3
4
使用案例:
MainActivity仍然是一个按钮,点击按钮打开SingleTopActivity,SingleTopActivity有两个按钮,一个是打开SingleTopActivity,一个是打开OtherActivity,OtherActivity有一个按钮,点击按钮能够打开SingleTopActivity。并且咱们在onCreate()、onNewIntent()打印taskId和hashCode值。

打开步骤:MainActivity->SingleTopActivity->SingleTopActivity->OtherActivity->SingleTopActivity->SingleTopActivity

MainActivity:

public class MainActivity extends AppCompatActivity {

private static final String TAG = MainActivity.class.getSimpleName();

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_demo);

findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SingleTopActivity.open(MainActivity.this);
}
});

Log.e(TAG, "———onCreate(): TaskId: " + getTaskId() +", hashCode: " + hashCode());

}

SingleTopActivity :

/**
* 启动模式:栈顶复用模式
*/

public class SingleTopActivity extends AppCompatActivity {

private static final String TAG = SingleTopActivity.class.getSimpleName();

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launch_mode);

findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
open(SingleTopActivity.this);
}
});
findViewById(R.id.btn_other).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
OtherActivity.open(SingleTopActivity.this);
}
});

Log.e(TAG, "———onCreate(): TaskId: " + getTaskId() +", hashCode: " + hashCode());
}

@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.e(TAG, "———onNewIntent(): TaskId: " + getTaskId() +", hashCode: " + hashCode());
}

public static void open(Context context) {
context.startActivity(new Intent(context, SingleTopActivity.class));
}

}

OtherActivity:

public class OtherActivity extends AppCompatActivity {

private static final String TAG = OtherActivity.class.getSimpleName();

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_other);

findViewById(R.id.btn_singleTop).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
SingleTopActivity.open(OtherActivity.this);
}
});

Log.e(TAG, "———onCreate(): TaskId: " + getTaskId() +", hashCode: " + hashCode());
}

public static void open(Context context) {
context.startActivity(new Intent(context, OtherActivity.class));
}

}

控制台打印log以下:

首先,由于它们的taskId值都相同,因此它们同属于一个任务栈。其次,第一次启动SingleTopActivity的时候会执行onCreate()方法新建一个实例,而后再次启动SingleTopActivity页面会回调onNewIntent(),说明没有建立新的实例,并且hashCode值没有发生改变。此时咱们继续打开另外一个Activity,这时OtherActivity处于栈顶,咱们继续启动SingleTopActivity,这时发现又是执行了onCreate(),说明又从新建立了新的实例,当咱们继续启动SingleTopActivity,发现回调了onNewIntent(),一样hashCode值没有发生改变,证实没有从新建立实例。

分析总结:
经过上述案例概括为如下三点:

一、当前栈中已有该Activity的实例而且该实例位于栈顶时,不会建立实例,而是复用栈顶的实例,而且会将Intent对象传入,回调onNewInten()方法;
二、当前栈中已有该Activity的实例可是该实例不在栈顶时,其行为和standard启动模式同样,依然会建立一个新的实例;
三、当前栈中不存在该Activity的实例时,其行为同standard启动模式。

使用场景:
这种模式应用场景的话,假如一个新闻客户端,在通知栏收到了3条推送,点击每一条推送会打开新闻的详情页,若是为默认的启动模式的话,点击一次打开一个页面,会打开三个详情页,这确定是不合理的。若是启动模式设置为singleTop,当点击第一条推送后,新闻详情页已经处于栈顶,当咱们第二条和第三条推送的时候,只须要经过Intent传入相应的内容便可,并不会从新打开新的页面,这样就能够避免重复打开页面了。

三、singleTask:站内复用模式
在这个模式下,若是栈中存在这个Activity的实例就会复用这个Activity,无论它是否位于栈顶,复用时,会将它上面的Activity所有出栈,由于singleTask自己自带clearTop这种功能。而且会回调该实例的onNewIntent()方法。其实这个过程还存在一个任务栈的匹配,由于这个模式启动时,会在本身须要的任务栈中寻找实例,这个任务栈就是经过taskAffinity属性指定。若是这个任务栈不存在,则会建立这个任务栈。不设置taskAffinity属性的话,默认为应用的包名。

使用案例:
MainActivity仍然是一个按钮,点击按钮打开SingleTaskActivity,SingleTaskActivity有两个按钮,一个是打开SingleTaskActivity,另外一个一样是打开OtherActivity,OtherActivity有一个按钮,点击按钮能够打开SingleTaskActivity。一样咱们在onCreate()、onNewIntent()打印taskId和hashCode值。

打开步骤:MainActivity->SingleTaskActivity->SingleTaskActivity->OtherActivity->SingleTaskActivity->SingleTaskActivity

代码和SingleTop基本同样,只有Manifest中配置不一样,这里再也不赘述。

一、不设置taskAffinity属性,也就是默在同一个任务栈中。

Manifest中配置:

<activity
android:name=".SingleTaskActivity"
android:launchMode="singleTask">
</activity>
1
2
3
4
控制台打印log以下:

首先,由于发现它们的taskId值都相同,因此它们同属于一个任务栈。其次,第一次启动SingleTaskActivity的时候会执行onCreate()方法新建一个实例,而后再次启动SingleTaskActivity页面会回调onNewIntent(),说明没有建立新的实例,并且hashCode值没有发生改变。此时咱们继续打开另外一个Activity,而后继续启动SingleTaskActivity,这时发现仍然只回调onNewIntent(),说明没有建立新的实例,当咱们继续启动SingleTaskActivity,仍然只是回调了onNewIntent(),此过程当中发现hashCode值始终没有发生改变,证实引用都是同一个的实例。

二、设置taskAffinity属性,singleTask所在的Activity与启动它的Activity处于不一样的任务栈中。

<activity
android:name=".SingleTaskActivity"
android:launchMode="singleTask"
android:taskAffinity="${applicationId}.singleTask">
</activity>

指定了taskAffinity后,咱们发现除了taskId有区别外,其余调用基本没有什么区别。由于MainActivity没有指定taskAffinity属性,默认为包名,与SingleTaskActivity不一样,因此在启动SingleTaskActivity时,发现这个栈不存在,系统首先会建立这个栈而后将SingleTaskActivity压入栈中。以后咱们发现只要栈中存在SingleTaskActivity这个实例,就会直接引用。

三、经过adb shell dumpsys activity activities查看当前运行的Activity

执行完上面的步骤,咱们经过上面的信息得出,发现只有MainActivity和SingleTaskActivity在运行,并且也能够看出确实有1909和1910两个任务栈。那OtherActivity哪去了?那是由于SingleTaskActivity具备ClearTop的功能,当复用SingleTashActivity的时候会将栈中SingleTaskActivity之上的Activity所有清掉,因此OtherActivity实际上是被销毁了。

分析总结:
在复用的时候,首先会根据taskAffinity去找对应的任务栈:
一、若是不存在指定的任务栈,系统会新建对应的任务栈,并新建Activity实例压入栈中。
二、若是存在指定的任务栈,则会查找该任务栈中是否存在该Activity实例
a、若是不存在该实例,则会在该任务栈中新建Activity实例。
b、若是存在该实例,则会直接引用,而且回调该实例的onNewIntent()方法。而且任务栈中该实例之上的Activity会被所有销毁。

使用场景:
SingleTask这种启动模式最常使用的就是一个APP的首页,由于通常为一个APP的第一个页面,且长时间保留在栈中,因此最适合设置singleTask启动模式来复用。

四、singleInstance:单实例模式
单实例模式,顾名思义,只有一个实例。该模式具有singleTask模式的全部特性外,与它的区别就是,这种模式下的Activity会单独占用一个Task栈,具备全局惟一性,即整个系统中就这么一个实例,因为栈内复用的特性,后续的请求均不会建立新的Activity实例,除非这个特殊的任务栈被销毁了。以singleInstance模式启动的Activity在整个系统中是单例的,若是在启动这样的Activiyt时,已经存在了一个实例,那么会把它所在的任务调度到前台,重用这个实例。

Manifest中配置:
<activity
android:name=".SingleInstanceActivity"
android:launchMode="singleInstance">
</activity>

使用案例:
使用上面一样的代码进行测试:

经过测试发现,在第一次打开SingleInstanceActivity的时候,因为系统不存在该实例,因此系统会新建一个任务栈来存放该Activity实例,并且只要打开过一次该Activity,后面不管何时再次启动该Activity,都会直接引用第一次建立的实例,并且会回调该实例的onNewIntent()方法。

分析总结:
启动该模式Activity的时候,会查找系统中是否存在:
一、不存在,首先会新建一个任务栈,其次建立该Activity实例。
二、存在,则会直接引用该实例,而且回调onNewIntent()方法。
特殊状况:该任务栈或该实例被销毁,系统会从新建立。

使用场景:
很常见的是,电话拨号盘页面,经过本身的应用或者其余应用打开拨打电话页面 ,只要系统的栈中存在该实例,那么就会直接调用。

3、总结在使用APP过程当中,不可避免页面之间的跳转,那么就会涉及到启动模式。其实在对界面进行跳转时,Android系统既能在同一个任务中对Activity进行调度,也能以Task(任务栈)为单位进行总体调度。在启动模式为standard或singleTop时,通常是在同一个任务中对Activity进行调度,而在启动模式为singleTask或singleInstance是,通常会对Task进行总体调度。

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章资源,如无特殊说明或标注,均为本站网友和创作者贡献分享。如若本站内容侵犯了原著者的合法权益,可联系网站客服QQ2743319061删除。

云炬星球 安卓教程 Android开发学习教程(24)- Android中Activity的启动模式(LaunchMode)和使用场景 https://src.yunjunet.cn/876807.html

常见问题
  • 放心亲,我们不会为了几十块钱的东西坏了名声!
查看详情
  • 方法一:点击“立即下载.”按钮,付款后在下载弹窗的虚线框的隐藏信息里获取 方法二:在正文底部使用VIP查看隐藏的解压密码 方法三:联系【云炬网络】公众号客服获取
查看详情
  • 付款后会出现“立即下载”按钮(点击即可下载),如果下载失败也可以联系客服发订单截图补发。
查看详情
  • 登录购买会多端同步购买记录,永久可以查看反复下载;非登录购买仅将购买记录保存到本地浏览器中,浏览器cookie清除后无法再次下载。先右上角点登录,然后点击微信图标可以快速授权注册登录^_^
查看详情
  • 可以试看。点击”查看演示“或“试看预览”按钮可以试读从资料目录中节选的部分内容,也可以自己指定想试看的内容。
查看详情
  • 原因一:本站所有资源已开启有效性检测(服务器24h全自动监测),当监测到下载链接无法访问时会提示“该资源已失效,请勿购买”,遇到这种情况可以联系客服修复失效的下载链接,或直接联系客服在淘宝下单购买即可。(检测原理:购买前服务器程序会预访问下载链接,响应值为200说明资源有效允许购买,响应值为404或502等报错说明资源失效禁止购买)。原因二:上传者未启用“下载”选项。
查看详情
官方客服团队

为您解决烦忧 - 24小时在线 专业服务