Activity系列:(一)烦人的Activity跳转

来源:互联网 发布:淘宝数码店铺简介 编辑:程序博客网 时间:2024/06/08 05:55

妹子我写代码很辛苦/(ㄒoㄒ)/~~ ,转载请注明出处哦~http://blog.csdn.net/u011791526/article/details/73650360

作者catRuan(阮妹子)

联系方式:QQ:940472401 邮箱:940472401@qq.com


      写项目的时候,往往很容易忽略activity的跳转关系,导致一些应该结束的activity实例没有结束。我一度陷入activity跳转混乱的局面,导致整个app的退回逻辑非常奇怪。因此痛定思痛,写下这篇文章,避免再犯如此低级的错误!


     一般的跳转逻辑

        ①、直接跳转,不销毁当前实例,这种情况适用于后面的activity回到当前activity时,当前activity需要保留此前的数据

        Intent intent = new Intent(this, targetAct);
        startActivity(intent);


        ②、跳转且销毁当前实例

         Intent intent = new Intent(this, targetAct);
         startActivity(intent);

         this.finish( );

         

         ③、跳转至下一个界面,不销毁当前实例,并在返回当前实例时获取后面activity返回的值,适用于两个activity有数据交互的情况

         Intent intent = new Intent(this, targetAct);
         startActivityForResult(intent, requestCode);


        使用启动模式控制逻辑

        原文地址:尊重他人劳动成果

        在AndroidManifest.xml里对应的<activity>标签设置Android:launchMode属性

         四种启动模式如下:

        standard
         默认模式,可以不用写配置。在这个模式下,都会默认创建一个新的实例。因此,在这种模式下,可以有多个相同的实例,也允许多个相同                  Activity叠加。
        

         singleTop
         可以有多个实例,但是不允许多个相同Activity叠加。即,如果Activity在栈顶的时候,启动相同的Activity,不会创建新的实例,而会调用其                    onNewIntent方法。

         例如:
         若我有两个Activity名为B1,B2,两个Activity内容功能完全相同,都有两个按钮可以跳到B1或者B2,唯一不同的是B1为standard,B2为singleTop。
         若我意图打开的顺序为B1->B2->B2,则实际打开的顺序为B1->B2(后一次意图打开B2,实际只调用了前一个的onNewIntent方法)
         若我意图打开的顺序为B1->B2->B1->B2,则实际打开的顺序与意图的一致,为B1->B2->B1->B2。


         singleTask
         只有一个实例。在同一个应用程序中启动他的时候,若Activity不存在,则会在当前task创建一个新的实例,若存在,则会把task中在其之上的其它        Activity destory掉并调用它的onNewIntent方法。
         如果是在别的应用程序中启动它,则会新建一个task,并在该task中启动这个Activity,singleTask允许别的Activity与其在一个task中共存,也就是 说,如果我在这个singleTask的实例中再打开新的Activity,这个新的Activity还是会在singleTask的实例的task中。

       例如:
       若我的应用程序中有三个Activity,C1,C2,C3,三个Activity可互相启动,其中C2为singleTask模式,那么,无论我在这个程序中如何点击启动,如: C1->C2->C3->C2->C3->C1-C2,C1,C3可能存在多个实例,但是C2只会存在一个,并且这三个Activity都在同一个task里面。
       但是C1->C2->C3->C2->C3->C1-C2,这样的操作过程实际应该是如下这样的,因为singleTask会把task中在其之上的其它Activity destory掉。
       操作:C1->C2          C1->C2->C3          C1->C2->C3->C2            C1->C2->C3->C2->C3->C1             C1->C2->C3->C2->C3->C1-C2
       实际:C1->C2          C1->C2->C3          C1->C2                              C1->C2->C3->C1                               C1->C2

       若是别的应用程序打开C2,则会新启一个task。
        如别的应用Other中有一个activity,taskId为200,从它打开C2,则C2的taskIdI不会为200,例如C2的taskId为201,那么再从C2打开C1、C3,则 C2、C3的taskId仍为201。
      注意:如果此时你点击home,然后再打开Other,发现这时显示的肯定会是Other应用中的内容,而不会是我们应用中的C1 C2 C3中的其中一个。

      singleInstance
      只有一个实例,并且这个实例独立运行在一个task中,这个task只有这个实例,不允许有别的Activity存在。

     例如:
     程序有三个ActivityD1,D2,D3,三个Activity可互相启动,其中D2为singleInstance模式。那么程序从D1开始运行,假设D1的taskId为200,那么从D1      启动D2时,D2会新启动一个task,即D2与D1不在一个task中运行。假设D2的taskId为201,再从D2启动D3时,D3的taskId为200,也就是说它被压      到了D1启动的任务栈中。

     若是在别的应用程序打开D2,假设Other的taskId为200,打开D2,D2会新建一个task运行,假设它的taskId为201,那么如果这时再从D2启动D1或      者D3,则又会再创建一个task,因此,若操作步骤为other->D2->D1,这过程就涉及到了3个task了。

       

      使用Flag控制跳转逻辑   

       affinity:

       拥有相同affinity的多个Activity理论同属于一个task,task自身的affinity决定于根Activity的affinity值。

       默认情况下,一个应用内的所有Activity都具有相同的affinity,都是从Application(参考<application>的taskAffinity属性)继承而来,而Application默认的affinity是<manifest>中的包名,我们可以为<application>设置taskAffinity属性值,这样可以应用到<application>下的所有<activity>,也可以单独为某个Activity设置taskAffinity。例如:在系统自带的Browser中,package为com.android.browser,但是<application>却自定义一个taskAffinity属性值:

       Flag是一些常用的标志,不同的Flag有不同的用途。例如:
       FLAG_ACTIVITY_NEW_TASK 
  
当Intent对象包含这个标记时,系统会寻找或创建一个新的task来放置目标Activity,寻找时依据目标Activity的taskAffinity属性进行匹配,如果找到一个task的taskAffinity与之相同,就将目标Activity压入此task中,如果查找无果,则创建一个新的task,并将该task的taskAffinity设置为目标Activity的taskActivity,将目标Activity放置于此task。注意,如果同一个应用中Activity的taskAffinity都使用默认值或都设置相同值时,应用内的Activity之间的跳转使用这个标记是没有意义的,因为当前应用task就是目标Activity最好的宿主。


       FLAG_ACTIVITY_CLEAR_TASK

       如果设置了此标识,这个标识将导致:在此activity启动之前,任何与此activity相关联的task都会被清除。也就是说,此
activity将变成一个空栈中新的最底端的activity,所有的旧activity都会被finish掉,这个标识仅仅和FLAG_ACTIVITY_NEW_TASK联合起来才能使用。


       FLAG_ACTIVITY_CLEAR_TOP 
  如果设置,并且这个Activity已经在当前的Task中运行,因此,不再是重新启动一个这个Activity的实例,而是在这个Activity上方的所有Activity都将关闭,然后这个Intent会作为一个新的Intent投递到老的Activity(现在位于顶端)中。 例如,假设一个Task中包含这些Activity:A,B,C,D。如果D调用了startActivity(),并且包含一个指向Activity B的Intent,那么,C和D都将结束,然后B接收到这个Intent,因此,目前stack的状况是:A,B。 上例中正在运行的Activity B既可以在onNewIntent()中接收到这个新的Intent,也可以把自己关闭然后重新启动来接收这个Intent。如果它的启动模式声明为“multiple”(默认值),并且你没有在这个Intent中设置FLAG_ACTIVITY_SINGLE_TOP标志,那么它将关闭然后重新创建;对于其它的启动模式,或者在这个Intent中设置FLAG_ACTIVITY_SINGLE_TOP标志,都将把这个Intent投递到当前这个实例的onNewIntent()中。 这个启动模式还可以与FLAG_ACTIVITY_NEW_TASK结合起来使用:用于启动一个Task中的根Activity,它会把那个Task中任何运行的实例带入前台,然后清除它直到根Activity。这非常有用,例如,当从Notification Manager处启动一个Activity。

       

       FLAG_ACTIVITY_SINGLE_TOP:
       当task中存在目标Activity实例并且位于栈的顶端时,不再创建一个新的,直接利用这个实例。
      目前发现与Activity启动模式中的singleTop效果相同。


.       FLAG_ACTIVITY_NO_HISTORY

      例如现在栈情况为:A B C。C通过intent跳转到D,这个intent添加FLAG_ACTIVITY_NO_HISTORY标志,则此时界面显示D的内容,但是它并不会压入栈中。如果按返回键,返回到C,栈的情况还是:A B C。如果此时D中又跳转到E,栈的情况变为:A B C E,此时按返回键会回到C,因为D根本就没有被压入栈中。简而言之,跳转到的activity不压在栈中。


       FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET 
  如果设置,这将在Task的Activity stack中设置一个还原点,当Task恢复时,需要清理Activity。也就是说,下一次Task带着FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标记进入前台时(典型的操作是用户在主画面重启它),这个Activity和它之上的都将关闭,以至于用户不能再返回到它们,但是可以回到之前的Activity。 这在你的程序有分割点的时候很有用。例如,一个e-mail应用程序可能有一个操作是查看一个附件,需要启动图片浏览Activity来显示。这个Activity应该作为e-mail应用程序Task的一部分,因为这是用户在这个Task中触发的操作。然而,当用户离开这个Task,然后从主画面选择e-mail app,我们可能希望回到查看的会话中,但不是查看图片附件,因为这让人困惑。通过在启动图片浏览时设定这个标志,浏览及其它启动的Activity在下次用户返回到mail程序时都将全部清除。
     

       FLAG_ACTIVITY_BROUGHT_TO_FRONT 
  这个标志一般不是由程序代码设置的,如在launchMode中设置singleTask模式时系统帮你设定。

       FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 
  如果设置,新的Activity不会在最近启动的Activity的列表中保存。

        LAG_ACTIVITY_FORWARD_RESULT 
  如果设置,并且这个Intent用于从一个存在的Activity启动一个新的Activity,那么,这个作为答复目标的Activity将会传到这个新的Activity中。这种方式下,新的Activity可以调用setResult(int),并且这个结果值将发送给那个作为答复目标的Activity。

       FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY 
  这个标志一般不由应用程序代码设置,如果这个Activity是从历史记录里启动的(常按HOME键),那么,系统会帮你设定。

      FLAG_ACTIVITY_MULTIPLE_TASK 
  不要使用这个标志,除非你自己实现了应用程序启动器。与FLAG_ACTIVITY_NEW_TASK结合起来使用,可以禁用把已存的Task送入前台的行为。当设置时,新的Task总是会启动来处理Intent,而不管这是是否已经有一个Task可以处理相同的事情。 由于默认的系统不包含图形Task管理功能,因此,你不应该使用这个标志,除非你提供给用户一种方式可以返回到已经启动的Task。 如果FLAG_ACTIVITY_NEW_TASK标志没有设置,这个标志被忽略。