Activity的启动模式及应用场景

启动模式的作用

在日常开发中,当默认情况下我们多次启动同一个Activity的时候,系统会创建多个实例并把它们一一放入任务栈,当我们每单击back键,就会栈顶移除一个Activity,直到栈空为止,当栈中没有任何Activity时,系统就会回收这个任务栈。为了优化多次启动同一个Activity而创建多个实例带来的内存消耗问题,Android提供了四种启动模式来修改默认行为。
目前四种启动模式分别是:standard、singleTop、singleTask、singleInstance;
为了方便分析了log日志打印,定义了一个基类:

/**
 * author:hzw on 2017/12/20
 * desc: 方便于打印的基类
 */

public class BaseActivity extends AppCompatActivity{

    public static final String TAG = "BaseActivity";


    private String getClassName(){
        return getClass().getSimpleName()+"--";
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       if (getSupportActionBar()!=null){
           getSupportActionBar().setTitle(getClassName());
       }

        Log.d(TAG, getClassName()+"onCreate(): taskId"+getTaskId());
       dumpTaskAffinity();

    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Log.i(TAG,getClassName()+"onNewIntent:  taskId"+getTaskId());
        dumpTaskAffinity();
    }

    protected void dumpTaskAffinity(){
        try {
            ActivityInfo info = this.getPackageManager()
                    .getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);
            Log.i(TAG, getClassName()+"taskAffinity:"+info.taskAffinity);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
    }
}

standard 默认模式

standard是标准模式,也是系统的默认模式。在不指定启动模式(LaunchMode)的情况下,系统会默认使用该启动模式,该模式的特点就是,每次启动一个Activity都会重新创建一个新的实例,不管这个Activity的实例是否已经存在。被创建的Activity的实例都会与正常典型的Activity生命周期一样的,比如onCreate、onStart、onResume方法都会被调用。这就是典型的多实例实现,一个任务栈中可以有多个实例,在这种模式下,谁启动了这个Activity,那么这个Activity就会在启动的那个Activity所在的栈中。

配置方式:

<activity android:name=".StandardActivity" android:launchMode="standard"/>

对于standard模式可以不用launchMode声明,系统默认情况下已经是standard了

测试案例
在NextActivity中启动一个StandardActivity,同时也在StandardActivity中再次启动一个StandardActivity

NextActivity :

public class NextActivity extends BaseActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_next);
        findViewById(R.id.bt_standard).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //标准模式 standard;
                Intent intent = new Intent(NextActivity.this, StandardActivity.class);
                startActivity(intent);
            }
        });
    }
}

StandardActivity :

public class StandardActivity extends BaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_standard);


        findViewById(R.id.bt_standard).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            //再次连续启动
                Intent intent = new Intent(StandardActivity.this, StandardActivity.class);
                startActivity(intent);
            }
        });

    }
}

在进入了StandardActivity后,再次连续启动StandardActivity,然后按back键依次退出。

这里写图片描述

Log日志输出:


03-26 15:09:27.367 3628-3628/com.hzw.tapp D/BaseActivity: NextActivity--onCreate()  taskId:7
03-26 15:09:27.367 3628-3628/com.hzw.tapp I/BaseActivity: NextActivity--taskAffinity:com.hzw.tapp
03-26 15:09:27.377 3628-3628/com.hzw.tapp I/BaseActivity: NextActivity--onStart()
03-26 15:09:27.377 3628-3628/com.hzw.tapp I/BaseActivity: NextActivity--onResume()
03-26 15:09:37.067 3628-3628/com.hzw.tapp I/BaseActivity: NextActivity--onPause()
03-26 15:09:37.077 3628-3628/com.hzw.tapp D/BaseActivity: StandardActivity--onCreate()  taskId:7
03-26 15:09:37.077 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--taskAffinity:com.hzw.tapp
03-26 15:09:37.077 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--onStart()
03-26 15:09:37.077 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--onResume()
03-26 15:09:37.447 3628-3628/com.hzw.tapp I/BaseActivity: NextActivity--onStop()
03-26 15:09:44.487 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--onPause()
03-26 15:09:44.497 3628-3628/com.hzw.tapp D/BaseActivity: StandardActivity--onCreate()  taskId:7
03-26 15:09:44.497 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--taskAffinity:com.hzw.tapp
03-26 15:09:44.497 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--onStart()
03-26 15:09:44.497 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--onResume()
03-26 15:09:44.877 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--onStop()
03-26 15:37:57.387 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--onPause()
03-26 15:37:57.397 3628-3628/com.hzw.tapp D/BaseActivity: StandardActivity--onCreate()  taskId:7
03-26 15:37:57.397 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--taskAffinity:com.hzw.tapp
03-26 15:37:57.397 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--onStart()
03-26 15:37:57.397 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--onResume()
03-26 15:37:57.797 3628-3628/com.hzw.tapp I/BaseActivity: StandardActivity--onStop()

从日志可以看出,启动了一次NextActivity和三次StandardActivity,而每次启动的StandardActivity的taskId都是与NextActivity的taskId一样的,由此可以证明谁启动了这个Activity,那么这个Activity就会在启动的那个Activity所在的栈中,同是每次启动StandardActivity,都会调用onCreate、onStart、onResume方法,证明了每次启动一个Activity都会创建一个新Activity实例。

singleTop 栈顶复用模式

在这个模式下,如果新Activity已经存在于任务栈栈顶,那么Activity不会被重新创建,同时它会调用onNewIntent方法,可以通过此方法可以取出所携带的信息,是不是调用onCreate、onStart方法;如果新Activity实例已存在但不在栈顶(或者新Activity在栈中不存在实例),那会新Activity依然重新创建一个实例。

配置方式

<activity android:name=".SingleTopActivity" android:launchMode="singleTop"/>

或者:

Intent intent = new Intent(NextActivity.this, SingleTopActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);

测试案例

SingleTopActivity:

public class SingleTopActivity extends BaseActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_single_top);

        String singleTop = getIntent().getStringExtra("singleTop");
        Log.i(TAG,singleTop+"");

        findViewById(R.id.bt_test_single_top).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //位于栈顶的情况
                Intent intent=new Intent(SingleTopActivity.this,SingleTopActivity.class);
                intent.putExtra("singleTop","singleTop");
                startActivity(intent);
            }
        });

        findViewById(R.id.bt_not_top).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //不在栈顶的情况
                startActivity(new Intent(SingleTopActivity.this,OtherTopActivity.class));
            }
        });
    }

}

这里写图片描述

OtherTopActivity :

public class OtherTopActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_other_top);

        findViewById(R.id.bt_single_top).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(OtherTopActivity.this,SingleTopActivity.class));
            }
        });
    }
}

这里写图片描述

第一种情况:新Activity位于栈顶

这里写图片描述

从日志上可见,当新Activity已经在栈顶时,再次启动,并不会调用新Activity的onCreate、onStart方法,可见此Activity并没有重新创建,只是调用了onNewIntent方法获取需要的信息,再去执行onResume方法得到焦点显示到前台。

第二种情况:新Activity已经存在于栈中,但不在栈顶

这里写图片描述
从日志可见,当新Activity已经存在于栈中,但不在栈顶,此时新Activity会重新创建一个实例,会调用典型的生命周期onCreate、onStart、onResume.

第三情况:就是当栈内不存在新Activity实例,此时同Standard模式一样的。

singleTask-栈内复用模式

singfleTask是一种单实例模式,就是只要栈中存在该Activity实例,那么多次启动该Activity都不会创建新实例,和singleTop一样,系统会回调其onNewIntent方法。同时singleTask启动模式与TaskAffinity属性有直接的关系。

TaskAffinity称为任务相关性,这个参数标识一个Activity所需要的任务栈名字,默认情况下,所以Activity所需的任务栈名字为应用的包名,当然,也可以为每个Activity都单独指定TaskAffinity属性,这个属性必须不能和包名相同,否则就相当于没有指定。

接下分析下TaskAffinity与singleTask启动模式的相关性

第一种情况:当ActivityA与ActivityB的TaskAffinity相同时

先在AndroidMainfest文件中为Activity指定相同的TaskAffinity属性值,都为应用包名。

<activity android:name=".NextActivity"
          android:taskAffinity="com.hzw.tapp"/>

 <activity
            android:name=".SingleTaskActivity"
            android:launchMode="singleTask"
            android:taskAffinity="com.hzw.tapp"/>

<activity android:name=".OtherTaskActivity"/>

这里写图片描述

从日志上可见,使用singleTask启动模式,当任务栈中存在Activity实例时,此时再次启动该Activity并不会重新创建新实例,而是复用之前该Activity的实例,并调用onNewIntent方法获取相关信息,同时也会把该Activity之上所有的activity实例从任务栈中移除销毁,使该Activity保持在栈顶中;当任务栈中不存在该Activity实例,此时会创建一个Activity实例放入该任务栈中。

第二种情况:当ActivityA与ActivityB的TaskAffinity属性值不同时

<activity android:name=".NextActivity"
          android:taskAffinity="com.hzw.tapp"/>

<activity
          android:name=".SingleTaskActivity"
          android:launchMode="singleTask"
          android:taskAffinity="com.hzw.tapp.task"/>

 <activity android:name=".OtherTaskActivity"/>

这里写图片描述

NextActivity启动SingleTaskActivity,TaskAffinity属性值不同时,系统会先创建一个所需的任务栈(com.hzw.tapp.task),然后再创建SingleTaskActivity的实例并将其放入任务栈(com.hzw.tapp.task)中,这点是与情况一的不同之处。

singleInstance 单实例模式

singleTask模式其实就是singleTask的加强版,它除了具有singleTask模式所有特性外,还加强一点就是在此模式下的Activity只能单独在一个任务栈中。

 <activity
            android:name=".SingleInstanceActivity"
            android:launchMode="singleInstance"/>

这里写图片描述

从日志可见,当NextActivity启动SingleInstanceActivity时,两者的taskId是不一样的,新建了一个任务栈,同时在SingleInstanceActivity中再次启动一个SingleInstanceActivity,此时可以看出,是不会重新创建一个任务栈和Activity实例,都是复用之前的,Activity会调用onNewIntent方法,这和singleTask模式是一样的。

猜你喜欢

转载自blog.csdn.net/hzw2017/article/details/79706394