一、 activity的启动方式分为两种显示启动和隐式启动

1、显示启动方式:

A:最常见的

MainActivity是当前的activity类,TargetActivity类是需要跳转到的类

startActivity(new Intent(MainActivity.this,TargetActivity.class));

 

B:通过Intent的ComponentName

ComponentName cn = new ComponentName("MainActivity的全类名","TargetActivity的全类名") ; Intent intent = new Intent() ; intent.setComponent(cn) ; startActivity(intent) ;

 

C:初始化Intent时指定包名

Intent intent = new Intent("android.intent.action.MAIN"); intent.setClassName("MainActivity的全限定类名","TargetActivity的全限定类名"); startActivity(intent);

 

2、隐式启动:

通过Intent-filter的Action,Category或data来实现,这个是通过Intent的intent-filter来实现

AndroidManifest.xml中定义被启动类的过滤条件

 

MainActivity.java中启动代码:

Intent intent = new Intent(); intent.setAction("my_action"); intent.addCategory("my_category"); startActivity(intent);

 

3. 通过包名启动apk

Intent intent = getPackageManager().getLaunchIntentForPackage("第一个启动的apk activity的全类名") ; if(intent != null) startActivity(intent) ;

 

二、Acitivity的四种启动模式

一、在将启动模式之前必须了解的一些知识:

    在正式的介绍Activity的启动模式之前,我们首先要了解一些旁边的知识,这些知识如果说模糊不清,那么在讨论启动模式的时候会一头雾水(笔者亲身感悟)。

 

1.一个应用程序通常会有多个Activity,这些Activity都有一个对应的action(如MainActivity的action),我们可以通过action来启动对应Activity(隐式启动)。

 

2.一个应用程序可以说由一系列组件组成,这些组件以进程为载体,相互协作实现App功能。

 

3.任务栈(Task Stack)或者叫退回栈(Back Stack)介绍:

 

3.1.任务栈用来存放用户开启的Activity。

 

3.2.在应用程序创建之初,系统会默认分配给其一个任务栈(默认一个),并存储根Activity。

 

3.3.同一个Task Stack,只要不在栈顶,就是onStop状态:

 

 

 

3.4.任务栈的id自增长型,是Integer类型。

 

3.5.新创建Activity会被压入栈顶。点击back会将栈顶Activity弹出,并产生新的栈顶元素作为显示界面(onResume状态)。

 

3.6.当Task最后一个Activity被销毁时,对应的应用程序被关闭,清除Task栈,但是还会保留应用程序进程(狂点Back退出到Home界面后点击Menu会发现还有这个App的框框。个人理解应该是这个意思),再次点击进入应用会创建新的Task栈。

 

4.Activity的affinity:

 

4.1.affinity是Activity内的一个属性(在ManiFest中对应属性为taskAffinity)。默认情况下,拥有相同affinity的Activity属于同一个Task中。

 

4.2.Task也有affinity属性,它的affinity属性由根Activity(创建Task时第一个被压入栈的Activity)决定。

 

4.3.在默认情况下(我们什么都不设置),所有的Activity的affinity都从Application继承。也就是说Application同样有taskAffinity属性。

 

android:taskAffinity="gf.zy"

4.4.Application默认的affinity属性为Manifest的包名。

 

 

暂时就是这么多了,如果还有不妥的地方我会补充的。接下来我们来正式看Activity的启动模式:

 

二、Activity启动模式:

1.默认启动模式standard:

    该模式可以被设定,不在manifest设定时候,Activity的默认模式就是standard。在该模式下,启动的Activity会依照启动顺序被依次压入Task中:

 

 

 

上面这张图讲的已经很清楚了,我想应该不用做什么实验来论证了吧,这个是最简单的一个,我们过。

 

2.栈顶复用模式singleTop:

    在该模式下,如果栈顶Activity为我们要新建的Activity(目标Activity),那么就不会重复创建新的Activity。

 

 

 

这次我来用代码举例:

 

<?xml version="1.0" encoding="utf-8"?>

package="zy.pers.activitytext">

android:allowBackup="true"

android:icon="@mipmap/ic_launcher"

android:label="@string/app_name"

android:roundIcon="@mipmap/ic_launcher_round"

android:supportsRtl="true"

android:taskAffinity="gf.zy"

android:theme="@style/AppTheme">

android:launchMode="singleTop">

这是我的第一个应用OneText的Mainfest结构,里面创建了三个Activity,我们把第二个Activity的模式设置为singleTop。

 

每个Activity界面都只有一个显示当前界面名称的TextView和一个用来组跳转的Button,所以应用OneText的功能就是从活动1跳转到活动2,活动2继续跳转活动2,代码就不给大家展示了,都能写出来。

 

 

 

我们发现在我们跳转到TwoActivity之后,点击跳转新的TwoActivity时候,他没有响应。

 

为了作对比,我们再把TwoActivity设置为standard,看一看效果:

 

 

 

我们发现创建了很多的TwoActivity。

 

同时我们打印上task的Id(我没有把所有周期方法都打印log):

 

 

 

发现他们全部都是来自一个Task。这个可以过。

 

应用场景:

 

开启渠道多,适合多应用开启调用的Activity:通过这种设置可以避免已经创建过的Activity被重复创建(多数通过动态设置使用,关于动态设置下面会详细介绍)

 

3.栈内复用模式singleTask:

    与singleTop模式相似,只不过singleTop模式是只是针对栈顶的元素,而singleTask模式下,如果task栈内存在目标Activity实例,则:

 

将task内的对应Activity实例之上的所有Activity弹出栈。

将对应Activity置于栈顶,获得焦点。

 

 

同样我们也用代码来实现一下这个过程:

 

还是刚才的那一坨代码,只是我们修改一下Activity1的模式为singleTask,然后让Activity2跳转到Activity3,让Activity3跳转到Activity1:

 

 

 

在跳回MainActivity之后点击back键发现直接退出引用了,这说明此时的MainActivity为task内的最后一个Activity。所以这个模式过。

 

应用场景:

 

程序主界面,我们肯定不希望主界面被多创建,而且在主界面退出的时候退出整个App是最好的设想。

 

耗费系统资源的Activity:对于那些及其耗费系统资源的Activity,我们可以考虑将其设为singleTask模式,减少资源耗费(在创建阶段耗费资源的情况,个人理解-。+)。

 

4.全局唯一模式singleInstance:

    这是我们最后的一种启动模式,也是我们最恶心的一种模式:在该模式下,我们会为目标Activity分配一个新的affinity,并创建一个新的Task栈,将目标Activity放入新的Task,并让目标Activity获得焦点。新的Task有且只有这一个Activity实例。       如果已经创建过目标Activity实例,则不会创建新的Task,而是将以前创建过的Activity唤醒(对应Task设为Foreground状态)

 

 

 

我们为了看的更明确,这次不按照上图的步骤设计程序了(没错,这几张图都不是我画的-。+!)。

 

我们先指定一下这次的程序:还是这三个Activity,这次Activity3设置为singleInstance,1和2默认(standard)。

 

然后我们看一下这个效果:

 

 

 

说一下我们做了什么操作:

 

首先由1创建2,2创建3,然后又由3创建2,2创建3,3创建2,然后一直back,图如下:

 

 

 

还请各位别嫌弃我-。+,图虽然不好看,但是很生动形象。。。。具体说一下:这张图对应着我们上面的程序流程,黄色的代表Background的Task,蓝色的代表Foreground的Task。

 

我们发现back的时候会先把Foreground的Task中的Activity弹出,直到Task销毁,然后才将Background的Task唤到前台,所以最后将Activity3销毁之后,会直接退出应用。

 

但是有没有想过这样会出现一个问题,什么问题我们直接看图就好:

 

 

 

我简单说一下这个案例:1,2,3三个Activity,2是singleInstance模式,然后1->2,2->3,之后狂点back,在回到Home界面后点击菜单键,发现首先启动的是2Activity。

 

简单解释一下:1和3是一个task,2是单独的一个task,在我们2->3后,前台的task又从2的回到了1和3的。所以最后退出的task是2的线程,而如果不是重新启动App。上一次最后关闭的Task是2的,所以。。

 

所以说singleInstance设置的Activity最好不要设置成中间界面。

 

 

 

以上表示我们关于四种模式的最基本理解,其实有了前面的知识了解之后,我们发现这些其实也不是很难对吧。。。真正比较绕的在后面-。+,注意前方高能:

 

三、动态设置启动模式

    在上述所有情况,都是我们在Manifest中设置的(通过launchMode属性设置),这个被称为静态设置(我们写程序写多了会发现有静态就有动态,而且静态多数在xml设置,动态在java代码设置-。+),接下来我们来看一下如何动态的设置Activity启动方式。

 

注):如果同时有动态和静态设置,那么动态的优先级更高。

 

1.关于动态设置与静态设置的理解:

    关于这个理解我是看过一篇文章,比较认同里面的思想,所以在这里也总结一下:

 

    静态设置,可以理解为通知别人:就是当我被创建的时候,我告诉你我是通过这种模式启动的。

 

    动态设置,可以理解为别人的要求:别人给我设一个Flag,我就以这种Flag的方式启动。

 

    可能这个没什么用哈,但是仔细想一下这种对程序的思想理解应该是正确的。

 

2.几种常见的Flag:

    我们说的动态设置,其实是通过Intent。对与Intent这个类大家应该不陌生吧,我们刚才在启动Activity的时候就用到这个类了。

 

如果我们要设置要启动的Activity的启动模式的话,只需要这样:

 

intent.setFlags(、、、、、);

然后在里面添加对应的Flag就好,那么接下来我们介绍几个常见的Flag(他的Flag太多了,头皮发麻。):

 

2.1._NEW_TASK

 

他对应的Flag如下:

 

Intent.FLAG_ACTIVITY_NEW_TASK

这个Flag跟我们的singleInstance很相似:在给目标Activity设立此Flag后,会根据目标Activity的affinity进行匹配:如果已经存在与其affinity相同的task,则将目标Activity压入此Task。    反之没有的话,则新建一个task,新建的task的affinity值与目标Activity相同。然后将目标Activity压入此栈。

 

其实简单来说,就是先看看需不需要创建一个新的Task,根据就是有没有相同的affinity。然后把Activity放进去。

 

但是此情况和singleInstance有不同,有两点注意的地方:

 

新的Task没有说只能存放一个目标Activity。只是说决定是否新建一个Task。而singleInstance模式下新的Task只能放置一个目标Activity。

在同一应用下,如果Activity都是默认的affinity,那么此Flag无效。而singleInstance默认情况也会创建新的Task。

这个东西理解起来可能有一些抽象,我们通过一个实例来证明他:

 

在之前的一些例子中,我们都是在同一应用之间进行跳转,而现在我们进行不同App的Activity相互跳转(其实就是创造一个不同taskAffinity的情况。。。忘了的话见一、4)。

 

首先,我们需要创建一个新的App——TwoApp,这个App目前只需要一个MainActivity就够了,我们在MainActivity放置一个button,让他跳转到OneApp的TwoActivity。

 

public void onClick(View v) {

Intent intent = new Intent("ONETEXT_TWOACTIVITY");

startActivity(intent);

}

这是跳转的代码。

 

现在我们先概述一下我们的流程:我们先打开TwoApp,然后在TwoApp的MainActivity界面跳转到OneApp的TwoActivity。

 

对于OneApp的设定,我们已经将三个Activity都设置成了standard模式。还是1->2,2->3,3->2。

 

代码就不上了,这么简单,大家自己也能写出来。效果如下:

 

为了看的清清楚楚,最开始清空了所有的进程。

 

现在我们点开TwoApp,

 

现在只有TwoApp一个进程,

 

现在我们点开了 OneApp的TwoActivity,但是我们发现他还是只有一个进程,

 

 

 

现在我们在TwoApp的MainActivity跳转到OneApp的TwoActivity,添加_NEW_TASK的Flag。

 

public void onClick(View v) {

Intent intent = new Intent("ONETEXT_TWOACTIVITY");

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

startActivity(intent);

}

我们再看一下效果,还是跟刚才一样先清空所有的进程,这次效果直接连起来看了:

 

 

 

与上面不同的地方在于,我们新的界面创建在了新的进程中——其实就是OneApp被唤醒了,我们来分析一下为什么会这样:

 

首先我们会想一下我们上面所学过的一个东西,affinity:我们说这个东西在默认情况下就是App的包名packageName,而OneApp中的TwoActivity默认的affinity就是OneApp的包名。这里能够理解吧。

 

然后我们说_NEW_TASK情况下,会先查找是否有对应的affinity的task,如果有就不在创建,直接将其放入,反之新建task,所以新建的task就是我们的OneApp的task,我们可以再做一个测试,我们先唤醒OneApp,然后再让TwoApp跳转到OneApp的TwoActivity(有点绕啊。。。),我们看是什么情况:

 

首先启动OneApp,并跳转到ThreeActivity。

 

然后启动TwoApp,并跳转到OneApp的TwoActivity。

 

然后一直点击Back,

 

我们发现在Two中唤醒One的TwoActivity,同样是被放入了OneApp的默认Task中。

 

关于_NEW_TASK我们就说这么多吧。

 

2.2._SINGLE_TOP

 

该模式比较简单,对应Flag如下:

 

Intent.FLAG_ACTIVITY_SINGLE_TOP

次Flag与静态设置中的singleTop效果相同,所以请见二、2.

 

2.3._CLEAR_TOP

 

这个模式对应的Flag如下:

 

Intent.FLAG_ACTIVITY_CLEAR_TOP

当设置此Flag时,目标Activity会检查Task中是否存在此实例,如果没有则添加压入栈,

 

如果有,就将位于Task中的对应Activity其上的所有Activity弹出栈,此时有以下两种情况:

 

如果同时设置Flag_ACTIVITY_SINGLE_TOP,则直接使用栈内的对应Activity,

没有设置。。。。。。。,则将栈内的对应Activity销毁重新创建。

关于这个Flag,我们发现他和singleTask很像,准确的说,是在_CLEAR_TOP和_SINGLE_TOP同时设置的情况下,就是singleTask模式。

 

而唯一不同的一点就在于:他会销毁已存在的目标实例,再重新创建。这个我们通过打印一下生命周期就好。

 

这次我们只用OneApp就好了,还是1->2,2->3,3->2,这次我们将2的Flag设置为_CLEAR_TOP,看一下TwoActivity的生命周期。

 

 

 

我们的流程如下:1->2       2->3    3->2     2->3    3->2    back    back   然后就退出了,这说明在Task内2上面的3的确被弹出栈了。

 

然后我们再看一下2的日志:

 

 

 

我想在日志图片上面标注的很清楚了,我只截取了一部分日志,我们质疑3->2时候先销毁,后创建。

 

 

 

好,现在我们同时加上_SINGLE_TOP的Flag。

 

效果相同,我们只看log:

 

 

 

很明显,在3->2的时候,TwoActivity调用了onRestart方法,也就是栈顶复用了。

 

这个Flag过。

 

参考文章:https://blog.csdn.net/zy_jibai/article/details/80587083

 

 

更多相关文章

  1. Android Activity启动模式分析
  2. Android中activity的启动模式详解
  3. Android夜间模式官方api实现(AppCompatDelegate)
  4. day02 数据存储和界面展现(1)
  5. android 界面常亮设置
  6. android仿QQ登录界面
  7. Android 微信界面 Fragment
  8. Android基础知识学习——界面转换
  9. android设置全屏模式

随机推荐

  1. android adb root方法
  2. uni-app之APP和小程序微信授权方法
  3. 22、TTS技术
  4. Android(安卓)Toolbar 使用总结
  5. android网络传输的传送对象
  6. Android(安卓)ADB命令大全(通过ADB命令查
  7. Android(安卓)Weekly - 第 184 期
  8. 【已解决】BaseMultiItemQuickAdapter使
  9. Android的WebView的自动完成(Auto suggest
  10. 直播平台软件开发Android(安卓)Activity