美文网首页杂七杂八Android开发Android实战
Activity的启动模式、任务栈以及使用场景

Activity的启动模式、任务栈以及使用场景

作者: 涛涛123759 | 来源:发表于2018-04-10 10:00 被阅读24次

    一、任务栈:

    (1)程序打开时就创建了一个任务栈, 用于存储当前程序的activity,所有的activity属于一个任务栈。
    (2)一个任务栈包含了一个activity的集合, 去有序的选择哪一个activity和用户进行交互:只有在任务栈栈顶的activity才可以跟用户进行交互。
    (3)任务栈可以移动到后台, 并且保留了每一个activity的状态. 并且有序的给用户列出它们的任务, 而且还不丢失它们状态信息。
    (4)退出应用程序时:当把所有的任务栈中所有的activity清除出栈时,任务栈会被销毁,程序退出。

    二、任务栈的缺点:
    (1)每开启一次页面都会在任务栈中添加一个Activity,而只有任务栈中的Activity全部清除出栈时,任务栈被销毁,程序才会退出,这样就造成了用,户体验差, 需要点击多次返回才可以把程序退出了。
    (2)每开启一次页面都会在任务栈中添加一个Activity还会造成数据冗余, 重复数据太多, 会导致内存溢出的问题(OOM)。

    为了解决任务栈的缺点,我们引入了启动模式。

    启动模式(launchMode)在多个Activity跳转的过程中扮演着重要的角色,它可以决定是否生成新的Activity实例,是否重用已存在的Activity实例,是否和其他Activity实例公用一个task里。这里简单介绍一下task的概念,task是一个具有栈结构的对象,一个task可以管理多个Activity,启动一个应用,也就创建一个与之对应的task

    三、Android任务栈的四种模式和应用场景
    通过AcitivtyManifest标签来改变任务栈的默认行为

    android:launchMode="standard|singleInstance|singleTask|singleTop"来控制Acivity任务栈。
    

    任务栈是一种后进先出的结构。位于栈顶的Activity处于焦点状态,当按下back按钮的时候,栈内的Activity会一个一个的出栈,并且调用其onDestory()方法。如果栈内没有Activity,那么系统就会回收这个栈,每个APP默认只有一个栈,以APP的包名来命名.

    1、standard : 标准模式. 每次启动Activity都会创建一个新的Activity实例,并且将其压入任务栈栈顶,而不管这个Activity是否已经存在。Activity的启动三回调(onCreate()->onStart()->onResume())都会执行(默认)。

    2、singleTop : 栈顶复用模式. 这种模式下,如果新Activity已经位于任务栈的栈顶,那么此Activity不会被重新创建,所以它的启动三回调就不会执行,同时Activity的onNewIntent()方法会被回调.如果Activity已经存在但是不在栈顶,那么作用于standard模式一样。

    3、singleTask: 栈内复用模式. 创建这样的Activity的时候,系统会先确认它所需任务栈已经创建,否则先创建任务栈.然后放入Activity,如果栈中已经有一个Activity实例,那么这个Activity就会被调到栈顶,onNewIntent(),并且singleTask会清理在当前Activity上面的所有Activity.(clear top)。

    4、singleInstance : 加强版的singleTask模式, 这种模式的Activity只能单独位于一个任务栈内,由于栈内复用的特性,后续请求均不会创建新的Activity,除非这个独特的任务栈被系统销毁了。
    获取栈的ID:this.getTaskId()

    我们看到从MainActivity跳转到SecondActivity时,重新启用了一个新的栈结构,来放置SecondActivity实例,然后按下后退键,再次回到原始栈结构;图中下半部分显示的在SecondActivity中再次跳转到MainActivity,这个时候系统会在原始栈结构中生成一个MainActivity实例,然后回退两次,注意,并没有退出,而是回到了SecondActivity,为什么呢?是因为从SecondActivity跳转到MainActivity的时候,我们的起点变成了SecondActivity实例所在的栈结构,这样一来,我们需要“回归”到这个栈结构。

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

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Log.e("---> : ", this.getTaskId() + "");
            processExtraData();
    
    
            findViewById(R.id.button).setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    clickText(v);
                }
            });
    
        }
    
        public void clickText(View view){
            Intent intent = new Intent(this,MainTwoActivity.class);
            startActivity(intent);
        }
    
    
        @Override
        protected void onNewIntent(Intent intent) {
            Log.i("test","onNewIntent...");
            Log.e("---> : ", this.getTaskId() + "");
            setIntent(intent);
            processExtraData();
            super.onNewIntent(intent);
        }
    
        private void processExtraData(){
            String value = getIntent().getStringExtra("test");
            Log.i("test","value===>"+value);
        }
    
    }
    

    public class MainTwoActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main_two);
        }
    
        @Override
        public boolean onKeyDown(int keyCode, KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_BACK){
                Intent intent = new Intent(this,MainActivity.class);
                intent.putExtra("test","hello...");
                startActivity(intent);
                return true;
            }
            return super.onKeyDown(keyCode, event);
    
        }
    
    
    }
    

    应用场景:

    singleTop 适合接收通知启动的内容显示页面。例如,某个新闻客户端的新闻内容页面,如果收到10个新闻推送,每次都打开一个新闻内容页面是很烦人的。

    singleTask 适合作为程序入口点。例如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面。之前打开过的页面,打开之前的页面就ok,不再新建。

    singleInstance 适合需要与程序分离开的页面。例如闹铃提醒,将闹铃提醒与闹铃设置分离。singleInstance不要用于中间页面,如果用于中间页面,跳转会有问题,比如:A -> B (singleInstance) -> C,完全退出后,在此启动,首先打开的是B。

    相关文章

      网友评论

        本文标题:Activity的启动模式、任务栈以及使用场景

        本文链接:https://www.haomeiwen.com/subject/hukghftx.html