一、 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系统开发小问题-启动过程中android字符没有显示出来
  2. android:launchMode="singleTask" 与 onNewIntent(Intent intent
  3. Android(安卓)Android(安卓)导入Flutter模块(二)-- 启动Flutter s
  4. Android(安卓)Activity启动模式分析
  5. Android(安卓)核心分析 之八------Android(安卓)启动过程详解
  6. Android中activity的启动模式详解
  7. 【Android(安卓)Training UI】创建自定义Views(Lesson 0 - 章节
  8. Android(安卓)studio 打不开官方虚拟机 100%成功解决方法
  9. android开机自启动apk

随机推荐

  1. android中menu.add()的使用说明
  2. Android(安卓)Studio一个连接SQLite数据
  3. Android(安卓)SDK目录结构和工具介绍
  4. Android上使用LibSVM
  5. Android(安卓)Thread Handler UIHandler
  6. Android实现随手指移动小球
  7. android 的混淆解析
  8. Android访问网络,HttpURLConnection还是Ht
  9. Android(安卓)Bitmap与Canvas
  10. Android程序检测网络是否可用