Android:四种启动模式分析

在一个项目中会包括着多个Activity,系统中使用任务栈来存储创建的Activity实例,任务栈是一种“后进先出”的栈结构。举个栗子,若我们多次启动同一个Activity。系统会创建多个实例依次放入任务栈中。当按back键返回时,每按一次,一个Activity出栈,直到栈空为止。当栈中无不论什么Activity。系统就会回收此任务栈。

上面这个样例中的Activity并没有设置启动模式,你会发现多次启动同一个Activity。而系统却创建了多个实例,白白浪费内存,这样的情况Android早就替我们考虑好了。Android为Activity 的创建提供了4种启动模式,而依据实际应用场景的不同。为Activity 选择不同的启动模式,最大化降低了每次都须要在栈中创建一个新的Activity的压力,降低内存使用。

启动模式的具体说明和使用场景?以下依据这篇博文来一一解惑。

一. Android启动模式具体解释

]![这里写图片描写叙述



1. Standard 标准模式

说明: Android创建Activity时的默认模式,假设没有为Activity设置启动模式的话,默觉得标准模式。每次启动一个Activity都会又一次创建一个新的实例入栈,无论这个实例是否存在。

生命周期:如上所看到的,每次被创建的实例Activity 的生命周期符合典型情况,它的onCreate、onStart、onResume都会被调用。

举例:此时Activity 栈中以此有A、B、C三个Activity,此时C处于栈顶,启动模式为Standard 模式。

若在C Activity中加入点击事件,须要跳转到还有一个同类型的C Activity。结果是还有一个C Activity进入栈中,成为栈顶。 
这里写图片描写叙述




2. SingleTop 栈顶复用模式

说明:分两种处理情况:须要创建的Activity已经处于栈顶时,此时会直接复用栈顶的Activity。不会再创建新的Activity;若须要创建的Activity不处于栈顶,此时会又一次创建一个新的Activity入栈,同Standard模式一样。

生命周期:若情况一中栈顶的Activity被直接复用时,它的onCreate、onStart不会被系统调用,由于它并没有发生改变。可是一个新的方法 onNewIntent会被回调(Activity被正常创建时不会回调此方法)。

举例:此时Activity 栈中以此有A、B、C三个Activity,此时C处于栈顶,启动模式为SingleTop 模式。情况一:在C Activity中加入点击事件,须要跳转到还有一个同类型的C Activity。

结果是直接复用栈顶的C Activity。

情况二:在C Activity中加入点击事件,须要跳转到还有一个A Activity。结果是创建一个新的Activity入栈。成为栈顶。


这里写图片描写叙述




3. SingleTask 栈内复用模式

说明:若须要创建的Activity已经处于栈中时,此时不会创建新的Activity,而是将存在栈中的Activity上面的其他Activity所有销毁,使它成为栈顶。

生命周期:同SingleTop 模式中的情况一同样。仅仅会又一次回调Activity中的 onNewIntent方法

举例:此时Activity 栈中以此有A、B、C三个Activity。此时C处于栈顶,启动模式为SingleTask 模式。

情况一:在C Activity中加入点击事件,须要跳转到还有一个同类型的C Activity。结果是直接用栈顶的C Activity。情况二:在C Activity中加入点击事件,须要跳转到还有一个A Activity。

结果是将A Activity上面的B、C所有销毁,使A Activity成为栈顶。 
这里写图片描写叙述




4. SingleInstance 单实例模式

说明: SingleInstance比較特殊,是全局单例模式,是一种加强的SingleTask模式。它除了具有它所有特性外,还加强了一点:具有此模式的Activity仅仅能单独位于一个任务栈中。

这个经常使用于系统中的应用,比如Launch、锁屏键的应用等等,整个系统中仅仅有一个!所以在我们的应用中一般不会用到。了解就可以。

举例:比方 A Activity是该模式,启动A后。系统会为它创建一个单独的任务栈,由于栈内复用的特性。兴许的请求均不会创建新的Activity,除非这个独特的任务栈被系统销毁。






二.启动模式的使用方式

1. 在 Manifest.xml中指定Activity启动模式

一种静态的指定方法,在Manifest.xml文件里声明Activity的同一时候指定它的启动模式,这样在代码中跳转时会依照指定的模式来创建Activity。样例例如以下:

        <activity android:name="..activity.MultiportActivity" android:launchMode="singleTask"/>
   
   

2. 启动Activity时。在Intent中指定启动模式去创建Activity

一种动态的启动模式,在new 一个Intent后,通过Intent的addFlags方法去动态指定一个启动模式。样例例如以下:


   
   
  1. Intent intent = new Intent() ;
  2. intent .setClass(context, MainActivity .class) ;
  3. intent .addFlags(Intent .FLAG_ACTIVITY_NEW_TASK) ;
  4. context .startActivity(intent) ;

注意:以上两种方式都能够为Activity指定启动模式,可是二者还是有差别的。

(1)优先级:动态指定方式即另外一种比第一种优先级要高,若两者同一时候存在,以另外一种方式为准。


(2)限定范围:第一种方式无法为Activity直接指定 FLAG_ACTIVITY_CLEAR_TOP 标识,另外一种方式无法为Activity指定 singleInstance 模式。





三. Activity 的 Flags

标记位既能够设定Activity的启动模式,如同上面介绍的,在动态指定启动模式,比方 FLAG_ACTIVITY_NEW_TASK 和 FLAG_ACTIVITY_SINGLE_TOP 等。它还能够影响Activity 的运行状态 ,比方 FLAG_ACTIVITY_CLEAN_TOP 和 FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 等。

以下介绍几个基本的标记位,切勿死记,理解几个就可以,须要时再查官方文档。

1. FLAG_ACTIVITY_NEW_TASK

作用是为Activity指定 “SingleTask”启动模式。跟在AndroidMainfest.xml指定效果同样。


2. FLAG_ACTIVITY_SINGLE_TOP

作用是为Activity指定 “SingleTop”启动模式,跟在AndroidMainfest.xml指定效果同样。


3. FLAG_ACTIVITY_CLEAN_TOP

具有此标记位的Activity,启动时会将与该Activity在同一任务栈的其他Activity出栈。一般与SingleTask启动模式一起出现。它会完毕SingleTask的作用。但事实上SingleTask启动模式默认具有此标记位的作用


4.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

具有此标记位的Activity不会出如今历史Activity的列表中,使用场景:当某些情况下我们不希望用户通过历史列表回到Activity时,此标记位便体现了它的效果。它等同于在xml中指定Activity的属性:

android:excludeFromRecents="trure"
   
   




四. 启动模式的实际应用场景

这四种模式中的Standard模式是最普通的一种,没有什么特别注意。而SingleInstance模式是整个系统的单例模式,在我们的应用中一般不会应用到。所以,这里就具体解说 SingleTop 和 SingleTask模式的运用场景:

1. SingleTask模式的运用场景

最常见的应用场景就是保持我们应用开启后仅仅有一个Activity的实例。最典型的样例就是应用中展示的主页(Home页)。

假设用户在主页跳转到其他页面,运行多次操作后想返回到主页,假设不使用SingleTask模式,在点击返回的过程中会多次看到主页,这明显就是设计不合理了。




2. SingleTop模式的运用场景

假设你在当前的Activity中又要启动同类型的Activity,此时建议将此类型Activity的启动模式指定为SingleTop,能够降低Activity的创建,节省内存!




3. 注意:复用Activity时的生命周期回调

这里还须要考虑一个Activity跳转时携带页面參数的问题。

由于当一个Activity设置了SingleTop或者SingleTask模式后,跳转此Activity出现复用原有Activity的情况时,此Activity的onCreate方法将不会再次运行。onCreate方法仅仅会在第一次创建Activity时被运行。

而一般onCreate方法中会进行该页面的数据初始化、UI初始化,假设页面的展示数据无关页面跳转传递的參数,则不必操心此问题,若页面展示的数据就是通过getInten() 方法来获取,那么问题就会出现:getInten()获取的一直都是老数据,根本无法接收跳转时传送的新数据!

以下,通过一个样例来具体解释:


   
   
  1. Manifest.xml
  2. <activity
  3. android:name = ".activity.CourseDetailActivity"
  4. android:launchMode = "singleTop"
  5. android:screenOrientation = "portrait" />

   
   
  1. public class CourseDetailActivity extends BaseActivity{
  2. ......
  3. @Override
  4. protected void onCreate (Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_course_detail_layout);
  7. initData();
  8. initView();
  9. }
  10. //初始化数据
  11. private void initData () {
  12. Intent intent = getIntent();
  13. mCourseID = intent.getStringExtra(COURSE_ID);
  14. }
  15. //初始化UI
  16. private void initView () {
  17. ......
  18. }
  19. ......
  20. }

以上代码中的CourseDetailActivity在配置文件里设置了启动模式是SingleTop模式,依据上面启动模式的介绍可得知,当CourseDetailActivity处于栈顶时。再次跳转页面到CourseDetailActivity时会直接复用原有的Activity,并且此页面须要展示的数据是从getIntent()方法得来,可是initData()方法不会再次被调用,此时页面就无法显示新的数据。

当然这样的情况系统早就为我们想过了,这时我们须要另外一个回调 onNewIntent(Intent intent)方法。此方法会传入最新的intent,这样我们就能够解决上述问题。这里建议的方法是又一次去setIntent。然后又一次去初始化数据和UI。代码例如以下所看到的:


   
   
  1. /*
  2. * 复用Activity时的生命周期回调
  3. */
  4. @Override
  5. protected void onNewIntent (Intent intent) {
  6. super.onNewIntent(intent);
  7. setIntent(intent);
  8. initData();
  9. initView();
  10. }

这样,在一个页面中能够反复跳转并显示不同的内容。

那么onNewIntent都会在什么情况下调用呢?

前提:ActivityA已经启动过,处于当前应用的Activity堆栈中; 

当ActivityA的LaunchMode为SingleTop时,如果ActivityA在栈顶,且现在要再启动ActivityA,这时会调用onNewIntent()方法 

当ActivityA的LaunchMode为SingleInstance,SingleTask时,如果已经ActivityA已经在堆栈中,那么此时会调用onNewIntent()方法 

当ActivityA的LaunchMode为Standard时,由于每次启动ActivityA都是启动新的实例,和原来启动的没关系,所以不会调用原来ActivityA的onNewIntent方法

And 生命周期流程

singleInstance:
第一次进入:onCreate onStart
在栈顶再次进入: onNewIntent
不在栈顶再次进入:onNewIntent onRestart onStart
按home键再次进入:onRestart onStart

standard:
第一次进入:onCreate onStart
在栈顶再次进入: onCreate onStart
不在栈顶再次进入:onCreate onStart

按home键  onPause--onSaveInstanceState--onStop(未勾选“不保留活动‘’)


             勾选了的话  onPause--onSaveInstanceState--onStop--onDestroy

再次进入(未勾选“不保留活动‘’): 主activity  onNewIntent--onRestart-onStart    

 非主activity onRestart-onStart  

按返回键:onPause--onStop--onDestroy (不走save了)重新进入onCreate onStart


singleTop:
第一次进入:onCreate onStart
在栈顶再次进入:onNewIntent
不在栈顶再次进入:onCreate onStart
按home键   再次进入:onRestart onStart



singleTask:
第一次进入:onCreate onStart
在栈顶再次进入:onNewIntent
不在栈顶再次进入:onNewIntent onRestart onStart
按home键再次进入:onRestart onStart



Activity的四种启动模式:  
    1. standard  
        默认启动模式,每次激活Activity时都会创建Activity,并放入任务栈中,永远不会调用onNewIntent()。  
    2. singleTop  
        如果在任务的栈顶正好存在该Activity的实例, 就重用该实例,并调用其onNewIntent(),否者就会创建新的实例并放入栈顶(即使栈中已经存在该Activity实例,只要不在栈顶,都会创建实例,而不会调用onNewIntent(),此时就跟standard模式一样)。  
    3. singleTask  
        如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的onNewIntent())。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移除栈。如果栈中不存在该实例,将会创建新的实例放入栈中(此时不会调用onNewIntent())。   
    4. singleInstance  
        在一个新栈中创建该Activity实例,并让多个应用共享改栈中的该Activity实例。一旦改模式的Activity的实例存在于某个栈中,任何应用再激活改Activity时都会重用该栈中的实例,其效果相当于多个应用程序共享一个应用,不管谁激活该Activity都会进入同一个应用中。  


当调用到onNewIntent(intent)的时候,需要在onNewIntent() 中使用setIntent(intent)赋值给Activity的Intent.否则,后续的getIntent()都是得到老的Intent。




  •                     <li class="tool-item tool-active is-like "><a href="javascript:;"><svg class="icon" aria-hidden="true">
                            <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#csdnc-thumbsup"></use>
                        </svg><span class="name">点赞</span>
                        <span class="count">1</span>
                        </a></li>
                        <li class="tool-item tool-active is-collection "><a href="javascript:;" data-report-click="{&quot;mod&quot;:&quot;popu_824&quot;}"><svg class="icon" aria-hidden="true">
                            <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#icon-csdnc-Collection-G"></use>
                        </svg><span class="name">收藏</span></a></li>
                        <li class="tool-item tool-active is-share"><a href="javascript:;"><svg class="icon" aria-hidden="true">
                            <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#icon-csdnc-fenxiang"></use>
                        </svg>分享</a></li>
                        <!--打赏开始-->
                                                <!--打赏结束-->
                                                <li class="tool-item tool-more">
                            <a>
                            <svg t="1575545411852" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5717" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M179.176 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5718"></path><path d="M509.684 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5719"></path><path d="M846.175 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5720"></path></svg>
                            </a>
                            <ul class="more-box">
                                <li class="item"><a class="article-report">文章举报</a></li>
                            </ul>
                        </li>
                                            </ul>
                </div>
                            </div>
            <div class="person-messagebox">
                <div class="left-message"><a href="https://blog.csdn.net/ElisonX">
                    <img src="https://profile.csdnimg.cn/A/C/3/3_elisonx" class="avatar_pic" username="ElisonX">
                                            <img src="https://g.csdnimg.cn/static/user-reg-year/2x/2.png" class="user-years">
                                    </a></div>
                <div class="middle-message">
                                        <div class="title"><span class="tit"><a href="https://blog.csdn.net/ElisonX" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}" target="_blank">ElisonX</a></span>
                                            </div>
                    <div class="text"><span>发布了18 篇原创文章</span> · <span>获赞 3</span> · <span>访问量 2万+</span></div>
                </div>
                                <div class="right-message">
                                            <a href="https://im.csdn.net/im/main.html?userName=ElisonX" target="_blank" class="btn btn-sm btn-red-hollow bt-button personal-letter">私信
                        </a>
                                                            <a class="btn btn-sm  bt-button personal-watch" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}">关注</a>
                                    </div>
                            </div>
        </div>
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值