3.Activity的启动模式与任务栈学习笔记

来源:互联网 发布:苹果制作铃声软件 编辑:程序博客网 时间:2024/05/16 00:47
    本来自认为对Activity启动模式已经很熟悉了,但是还是有一些忘了,所以在此我再次学习一遍。
    首先,Activity的启动模式分为四种,为了满足各种项目的需求,我们需要了解Activity的启动模式和标志位。

3.1 Activity的LaunchMode
    
    3.1.1 standard:标准模式,也就是系统的默认模式。
    每次启动一个Activity都会创建一个新的实例,不管这个Activity是否已经存在了实力,多次启动的Activity声明周期也是符合正常情况下的生命周期.这是一种典型的多实例实现,一个任务栈中可以有多个实例,每个实例也可以属于不同的任务栈。在这个情况下,谁启动了这个Activity,那么这个Activity就会运行在启动它的那个Activity所在的栈当中。
    在这里说明一种情况:使用ApplicationContext去启动Standard模式的Activity的时候,会报错,如下:
    android.util.AndroidRuntimeException:   Calling startActivity from outside of an Activity requires the FLAG_ACTIVITY_NEW_TASK flag.Is this really what you want ?
    这个错误经常会遇到,比如在一个广播当中直接用Context去启动一个新的标准的Activity.这个是因为,standard模式的Activity默认会进入启动它的Activity的任务栈,而非Activity类型的Context(比如ApplcationContext)是没有任务栈的,所以就会出现问题。解决这个就是启动的时候设置标志:FLAG_ACTIVITY_NEW_TASK。这样子就会为这个Activity创建一个单独的任务栈,这个时候待启动的Activity实际上是用singleTask来启动的(按照不存在的方式启动)。

    3.1.2 singleTop:栈顶复用模式。
    在这种情况下,如果要创建的Activity已经有实例位于任务栈的栈顶,那么就不会被重新创建,但是会调用这个Activity的onNewIntent方法(onCreate、onResume方法不会被调用),通过onNewIntent方法,我们可以从Intent当中取出请求的信息。

    3.1.3 singleTask:栈内复用模式。
    这是一种单实例模式,这种模式下,只要Activity一个栈中存在该Activity的实例,那么多次调用都不会创建新的实例,但是系统会调用它的onNewIntent。
    具体来哦说:当一个具有singleTask模式的Activity请求启动以后,比如Activity A,系统首先会寻找是否存在A想要的任务栈。如果不存在,就重新创建一个任务栈,如果不存在,就创建新的一个任务栈,然后创建A的实例放到栈中,如果存在,就看这个任务栈是否有A的实例存在,如果有实例存在,那么系统则会把A调到栈顶然后再移除该实例上面的Activity并且调用它的onNewIntent方法。如果A不在这个想要的任务栈中,那么就会创建A的实力并且把A压入栈中。
  • 比如任务栈S1有ABC,singleTask启动Activity D,D想进入S2,没有S2也没有D,那么就创建S2,并且把D放入S2中。
  • D所需要S1,S1存在,D不存在,那么就创建D放入S1。最后S1为ABCD
  • 再一种情况,S1存在,D也存在,D想进S1,顺序为ADBC,那么就会把D放到栈顶,而D前面的都会被clear掉。
   
    3.1.4 singInstance:单实例模式。
        这种模式是加强版本的singleTask模式,这种模式的Activity只能单独位于一个栈当中。
   
    3.1.5 指定启动模式
        指定启动模式有两种:一种是在AndroidManifest.xml中,在Activity声明里面指定启动模式比如:
<activity android:name=".Main2Activity"android:allowTaskReparenting="true"android:launchMode="singleTask"></activity>


    也可以通过再Intent中设置标志位来为Activity指定启动模式,如:
    Intent intent = new Intent();
    intent.setClass( MainActivity.Class,SecondActivity.class);
    startActivity( intent );
    
    这两种方式,都可以为Activity指定启动模式,但是两者还是有区别。
  • 优先级上:第二种高于第一种。
  • 限定范围不同,第一种无法直接为Activity标志:FLAG_ACTIVITY_CLEAR_TOP(但是singleTask默认具有这个功能),第二种无法为Activity指定singleInstance
    
3.2 任务栈

    什么是任务栈呢?要了解Task栈,就需要先了解:
  • Activity的affinity
  • Intent的Flag
  • Activity关于Task的属性    
    在此,我们先从参数TaskAffinity说起。

    3.2.1 TaskAffinity
            TaskAffinity可以翻译为:任务相关性。它是一个参数,这个参数标识了一个Activity所需要的任务栈的名字。也就是我们上面介绍SingleTask所说的需要的任务栈。默认情况下,这个所有Activity所需要的栈名就是包名(包名是唯一的)。当然,我们可以为每个Activity都单独制定TaskAffinity属性,这个属性值必须不能和包名一样(不只是自己的包名,和其他应用包名都不能重复),否则就相当于没有指定。TaskAffinity属性主要和singleTask启动模式或者allowTaskReparenting属性配对使用,在其他情况下没有意义。另外,任务栈又分:前台任务栈和后台任务栈。后台任务栈的Activity位于暂停状态,用户可以通过切换把后台任务栈再次调到前台。(如何调用呢?参考:http://blog.csdn.net/chaoyue0071/article/details/43791909  稍后也会进行解释
    
    当TaskAffinity和singleTask启动模式配对使用的时候,它是具有该模式的Activity的目前栈的名字,待启动的Activity会运行在名字和TaskAffinity相同的任务栈中。
    当TaskAffinity和allTaskReparenting结合的时候,会产生一些特殊的效果。比如应用A启动了应用B的某个Activity后,如果这个Activity的allTaskReparenting属性为True的话,那么当应用B被启动后,此Activity会直接从应用A的任务栈移到应用B的任务栈。   如:A应用和B应用,A应用启动了B的某一个Activity C,然后按Home回到了桌面,最后单击B应用,跳出来的是B应用的Activity C而不是MainActivity。  
    问题:TaskAffinity和singleTask搭配时候,和TaskAffinity +allTaskReparenting 有什么区别?     
    区别在于:前者创建Activity C的时候就会创建B的任务栈 ,而后者则是现在A的任务栈运行,等到了B启动,创建了任务栈B,那么就会把C从任务栈A移到任务栈B当中。   

3.2.2 Activity的常用Flags
  • FLAG_ACTIVITY_NEW_TASK
        指定Activity启动模式为"singleTask"模式,效果和在AndroidManifest.xml中指定该启动模式一样。
  • FLAG_ACTIVITY_SINGLE_TOP
        指定Activity启动模式为"singleTop"模式。
  • FLAG_ACTIVITY_CLEAR_TOP 
       使用这个标记位,启动Activity的时候,通一个任务栈上面所有位于它上面的Activity都会被弹出栈。singleTask模式默认有此效果。
  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
        这个Activity不会出现在历史Activity的列表当中,在一些情况下,我们不希望用户能通过历史列表找回这个Activity,那么我们可以使用这个标记位。可以在AndroidManifest.xml中使用android:excludeFromRecents="true"。B标记了,比如A->B->C,C按返回键会回到A。


3.3 前台任务栈和后台任务栈

       个人认为:前台任务栈是当前运行于前台的一组Activity的集合,也可以是Activity集合的集合,比如栈A运行于前台,栈B运行于后台,栈A调用栈B的Activity,那么,栈B就会运行到前台,并且栈B整个Activity列表叠在栈A的Activity列表上,如果一直按Back会清空栈B以后,才进入到栈A。而此时栈A、栈B都运行于前台。当按了Home键什么的,栈A和栈B就双双进入后台暂停运行。




0 0
原创粉丝点击