美文网首页
Activity四种启动模式及Intent flag

Activity四种启动模式及Intent flag

作者: Six_Cai | 来源:发表于2018-07-27 16:32 被阅读0次

    目录

    1. 四种启动模式
    2. 常用的四个flag
    3. 代码测试

    一、基础的四种启动模式

    standard模式(默认)

    每次启动时,都会新建一个实例

    singleTop模式

    如果Activity实例位于当前任务栈顶,就复用用栈顶实例并回调该实例onNewIntent()方法,否则走新建流程。

    singleInstance模式

    这种模式启动的Activity独自占用一个Task任务栈,同一时刻系统中只会存在一个实例,已存在的实例被再次启动时,只会唤起原实例,并回调onNewIntent()方法。

    singleTask模式

    如果未设置android:taskAffinity属性,当前的task中已经有其它的activity实例时,在第一次启动并不会新建一个task,只会去新建该activity的实例并压入该task中。
    如果当前的task中已经存在此activity,则会清理在此activity之上的所有activity实例,然后回调onNewIntent()方法.</br>
    如果设置了android:taskAffinity属性,第一次启动时,会新建task并将该Activity添加到task,
    如果当前的task中已经存在此activity,则会清理在此activity之上的所有activity实例,然后回调onNewIntent()方法. </br>
    同一时刻系统中只会存在一个实例。

    二、四种Flag的简介

    FLAG_ACTIVITY_SINGLE_TOP
    设置此flag时,当被启动的activity已经位于当前栈的顶部时,则不会新建Activity。

    FLAG_ACTIVITY_NEW_TASK <br />
    此flag是会让Activity在新的栈中启动。但是单独使用此flag时会有较多意想不到的情况发送
    1.使用场景:在非Activity中启动Activity需要强制加上此flag <br />
    单独使用此flag的情形: <br />
    1.Activity的taskAffinity属性的Task栈是否存在 <br />
    2.如果存在,要看Activity是否存已经存在于该Task <br />
    3.如果已经存在于该taskAffinity的Task,要看其是不是其rootActivity <br />
    4.如果是其rootActivity,还要看启动该Activity的Intent是否跟当前intent相等 <br />

    FLAG_ACTIVITY_CLEAR_TASK <br />
    此flag需要与FLAG_ACTIVITY_NEW_TASK结合使用。使用时会在Activity启动之前将task中其它Activity销毁(无论其它Activity设置了何种启动模式)

    FLAG_ACTIVITY_CLEAR_TOP <br />
    使用此flag时,如果当前task中存在待启动Activity的实例,则会清空此task中待启动activity及以上的activity。

    三、代码测试

    FLAG_ACTIVITY_NEW_TASK测试一(不指定taskAffinity)

    此示例中共有两个Activity,manifest定义如下

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="ttt.czh.com.activitylaunchtest">
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <activity android:name=".SecondActivity" />
        </application>
    
    </manifest>
    

    MainActivity的代码

    class MainActivity : AppCompatActivity() {
        
        val TAG : String = "MainActivity"
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            main_textview.text = this.toString() + " taskId = " + this.getTaskId()
            main_textview.setOnClickListener{
                var intent : Intent = Intent()
                intent.setClass(this, SecondActivity::class.java)
                //此处增加了FLAG_ACTIVITY_NEW_TASK的flag
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                startActivity(intent)
            }
        }
    
        override fun onNewIntent(intent: Intent?) {
            super.onNewIntent(intent)
            setIntent(intent)
    
            Log.d(TAG, "onNewIntent: intent = " + intent + " activity = " + this + " taskId = " + this.taskId)
        }
    }
    

    SecondActivity的代码

    public class SecondActivity extends Activity {
    
        private static final String TAG = "SecondActivity";
    
        private TextView mTextView;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_second);
            mTextView = (TextView) findViewById(R.id.textview);
    
            mTextView.setText(this.toString() + " taskId = " + this.getTaskId());
    
            mTextView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent intent = new Intent();
                    intent.setClass(SecondActivity.this, MainActivity.class);
                    startActivity(intent);
                }
            });
        }
    
        @Override
        protected void onNewIntent(Intent intent) {
            super.onNewIntent(intent);
            setIntent(intent);
    
            Log.d(TAG, "onNewIntent: intent = "+intent+" activity = "+this+" taskId = "+this.getTaskId());
        }
    }
    

    测试步骤 MainActivity-->SecondActivity-->MainActivity-->SecondActivity <br />
    结果:1)SecondActivity与MainActivity在同一个task中。2)两个SecondActivity为不同的对象 <br />
    结果分析:在相互跳转的两个Activity的android:taskAffinity相同的情况下,单独使用FLAG_ACTIVITY_NEW_TASK不会产生任何效果 <br />

    最终结果:


    FLAG_ACTIVITY_NEW_TASK测试一
    FLAG_ACTIVITY_NEW_TASK测试二(两个Activity设置不同的taskAffinity)

    在保持上面代码不变的前提下,修改manifest如下

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="ttt.czh.com.activitylaunchtest">
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <activity android:name=".SecondActivity"
                android:taskAffinity="com.czh.ttt.test">
            </activity>
        </application>
    
    </manifest>
    

    测试步骤 MainActivity-->SecondActivity-->MainActivity-->SecondActivity <br />
    结果:1)SecondActivity与MainActivity在不同的task中。2)当第二次尝试进入SecondActivity中时,会发现没有任何变化,仍然停留在MainActivity中 <br />

    结果分析:因为此时SecondActivity实例已经存在,但是它所在的task的栈顶是ActivityTest;而单独的添加FLAG_ACTIVITY_NEW_TASK又不会"删除task中位于SecondActivity之上的Activity实例",所以就没有发生跳转(onNewIntent也没有回调)。这种情况下只会将整个栈移动到前台,且栈中的状态不会改变。 <br />

    FLAG_ACTIVITY_NEW_TASK测试二
    FLAG_ACTIVITY_NEW_TASK测试三(两个Activity设置不同的taskAffinity并Service中启动SecondActivity)

    在保持上面代码不变的前提下,增加Service的代码并修改SecondActivity的点击事件代码

      mTextView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    //启动Service
                    Intent intent1 = new Intent();
                    intent1.setClass(SecondActivity.this,TestService.class);
                    startService(intent1);
                }
            });
    public class TestService extends Service {
    
        private static final String TAG = "TestService";
    
        private Handler mHandler = new Handler();
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
        
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    //延后两秒启动SecondActivity
                    Intent intent1 = new Intent();
                    intent1.setClass(TestService.this, SecondActivity.class);
                    intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(intent1);
                }
            }, 2000);
            return super.onStartCommand(intent, flags, startId);
        }
    }
    

    测试步骤 MainActivity-->SecondActivity-->TestService <br />
    结果:1)SecondActivity与MainActivity在不同的task中。2)两次启动的SecondActivity为相同的实例 <br />

    结果分析:第二次启动SecondActivity时,因为此时SecondActivity实例已经存在,并且它该栈是rootActivity;所以就没有重新创建(onNewIntent也没有回调)。这种情况下只会将整个栈移动到前台,且栈中的状态不会改变。 <br />

    FLAG_ACTIVITY_NEW_TASK测试三
    FLAG_ACTIVITY_NEW_TASK测试四(其它情形)
    FLAG_ACTIVITY_NEW_TASK测试四
    FLAG_ACTIVITY_CLEAR_TOP测试一(与NEW_TASK一起使用)

    修改FLAG_ACTIVITY_NEW_TASK测试一中的MainActivity点击事件为

     main_textview.setOnClickListener{
                var intent : Intent = Intent()
                intent.setClass(this, SecondActivity::class.java)
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                //增加FLAG_ACTIVITY_CLEAR_TOP的flag
                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
                startActivity(intent)
            }
    

    测试步骤 MainActivity-->SecondActivity-->MainActivity-->SecondActivity <br />
    结果:1)SecondActivity与MainActivity在同一个的task中。2)两个SecondActivity为不同的实例 <br />

    结果分析:在第二次启动SecondActivity时,会将SecondActivity及以上的activity清空,然后finish并re-create SecondActivity <br />


    FLAG_ACTIVITY_CLEAR_TOP测试一
    FLAG_ACTIVITY_CLEAR_TOP测试一(与NEW_TASK一起使用)

    修改FLAG_ACTIVITY_NEW_TASK测试一中的MainActivity点击事件为

     main_textview.setOnClickListener{
                var intent : Intent = Intent()
                intent.setClass(this, SecondActivity::class.java)
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                //增加FLAG_ACTIVITY_CLEAR_TOP的flag
                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
                startActivity(intent)
            }
    

    测试步骤 MainActivity-->SecondActivity-->MainActivity-->SecondActivity <br />
    结果:1)SecondActivity与MainActivity在同一个的task中。2)两个SecondActivity为不同的实例 <br />

    结果分析:在第二次启动SecondActivity时,会将SecondActivity及以上的activity清空,然后finish并re-create SecondActivity <br />


    FLAG_ACTIVITY_CLEAR_TOP测试一
    FLAG_ACTIVITY_CLEAR_TOP测试二

    在FLAG_ACTIVITY_NEW_TASK测试二的基础上,修改MainActivity的点击事件

     main_textview.setOnClickListener{
                var intent : Intent = Intent()
                intent.setClass(this, SecondActivity::class.java)
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                //增加FLAG_ACTIVITY_CLEAR_TOP的flag
                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
                startActivity(intent)
            }
    

    测试步骤 MainActivity-->SecondActivity-->MainActivity-->SecondActivity-->返回键-->返回键 <br />
    结果:1)SecondActivity与MainActivity在不同的task中。2)两个SecondActivity为不同的实例
    3)第一次返回,会回到MainActivity中 4)第二次返回,会回到MainActivity之前的界面 <br />

    FLAG_ACTIVITY_CLEAR_TOP测试二
    FLAG_ACTIVITY_CLEAR_TOP测试三(FLAG_ACTIVITY_CLEAR_TOP与FLAG_ACTIVITY_SINGLE_TOP一同使用)

    在FLAG_ACTIVITY_NEW_TASK测试一的基础上,修改MainActivity的点击事件代码。

          main_textview.setOnClickListener{
                var intent : Intent = Intent()
                intent.setClass(this, SecondActivity::class.java)
                //增加FLAG_ACTIVITY_SINGLE_TOP的标记
                intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
                startActivity(intent)
    

    测试步骤 MainActivity-->SecondActivity-->MainActivity-->SecondActivity-->返回键-->返回键 <br />
    结果:1)SecondActivity与MainActivity在同一个task中。2)两个SecondActivity为相同的实例
    3)第一次返回,会回到MainActivity中 4)第二次返回,会回到MainActivity之前的界面 <br />

    结果分析:因为第二次启动SecondActivity时,在当前的task中已经存在SecondActivity的实例,所以第二次启动时,SecondActivity不会被重建,而只会回调onNewIntent方法 <br />

    FLAG_ACTIVITY_CLEAR_TOP测试三
    FLAG_ACTIVITY_CLEAR_TOP测试四(单独使用且launchmode为standard)

    在FLAG_ACTIVITY_NEW_TASK测试一的基础上,修改MainActivity的点击事件代码。

          main_textview.setOnClickListener{
                var intent : Intent = Intent()
                intent.setClass(this, SecondActivity::class.java)
                //增加FLAG_ACTIVITY_SINGLE_TOP的标记
                intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
                startActivity(intent)
    

    测试步骤 MainActivity-->SecondActivity-->MainActivity-->SecondActivity-->返回键-->返回键 <br />
    结果:1)SecondActivity与MainActivity在同一个task中。2)两个SecondActivity为不同的实例
    3)第一次返回,会回到MainActivity中 4)第二次返回,会回到MainActivity之前的界面 <br />

    结果分析:因为第二次启动SecondActivity时,在当前的task中已经存在SecondActivity的实例,因为没有设置FLAG_ACTIVITY_SINGLE_TOP,所以SecondActivity会被销毁重建。(只会在目标activity所属的task中查找,并不会跨栈进行查找) <br />

    FLAG_ACTIVITY_CLEAR_TOP测试四
    FLAG_ACTIVITY_CLEAR_TASK测试一

    此flag必须与FLAG_ACTIVITY_NEW_TASK一同使用。修改FLAG_ACTIVITY_NEW_TASK测试一中的MainActivity点击事件为

         main_textview.setOnClickListener{
                var intent : Intent = Intent()
                intent.setClass(this, SecondActivity::class.java)
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
                startActivity(intent)
    

    测试步骤 MainActivity-->SecondActivity-->MainActivity-->SecondActivity --->点击back button <br />
    结果:1)SecondActivity与MainActivity在不同的task中。2)两个SecondActivity为不同的实例 3)点击返回按钮会直接回到MainActivity之前的界面 <br />

    FLAG_ACTIVITY_CLEAR_TASK测试一
    FLAG_ACTIVITY_CLEAR_TASK测试二

    此flag必须与FLAG_ACTIVITY_NEW_TASK一同使用。修改FLAG_ACTIVITY_NEW_TASK测试一中的MainActivity点击事件为

         main_textview.setOnClickListener{
                var intent : Intent = Intent()
                intent.setClass(this, SecondActivity::class.java)
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
                startActivity(intent)
    

    测试步骤 MainActivity-->SecondActivity-->MainActivity-->SecondActivity-->返回键-->返回键 <br />
    结果:1)SecondActivity与MainActivity在不同的task中。2)两个SecondActivity为不同的实例 3)第一次返回,会回到MainActivity中 4)第二次返回,会回到MainActivity之前的界面 <br />

    FLAG_ACTIVITY_CLEAR_TASK测试二
    SingleTask测试一(未设置taskAffinity)

    在FLAG_ACTIVITY_NEW_TASK测试一的基础上,修改manifest.xml及MainActivity的代码如下

    //AndroidManifest.xml
     <activity android:name=".SecondActivity"
                android:launchMode="singleTask">
     </activity>
     
     //MainActivity.java
            main_textview.setOnClickListener{
                var intent : Intent = Intent()
                intent.setClass(this, SecondActivity::class.java)
                startActivity(intent)
            }
    

    测试步骤 MainActivity-->SecondActivity-->MainActivity-->SecondActivity-->返回键-->返回键 <br />
    结果:1)SecondActivity与MainActivity在同一个的task中。2)两个SecondActivity为相同的实例 3)第一次返回,会回到MainActivity中 4)第二次返回,会回到MainActivity之前的界面 <br />
    结果分析:1)第一次启动SecondActivity时,由于设置了android:taskAffinity属性,所以会新建一个task并将SecondActivit压入该task中。
    2)第二次启动SecondActivity时,由于SecondActivity已经在当前的task中,所以启动时会将其之上的activity(此处为MainActivity)清理出栈,然后回调SecondActivity的onNewIntent方法。

    SingleTask测试一
    SingleTask测试二(设置taskAffinity)

    在FLAG_ACTIVITY_NEW_TASK测试一的基础上,修改manifest.xml及MainActivity的代码如下

    //AndroidManifest.xml
     <activity android:name=".SecondActivity"
                android:taskAffinity="com.czh.ttt.test"
                android:launchMode="singleTask">
     </activity>
     
     //MainActivity.java
       mTextView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent intent = new Intent();
                    intent.setClass(SecondActivity.this, MainActivity.class);
                    startActivity(intent);
                }
            });
    

    测试步骤 MainActivity-->SecondActivity-->MainActivity-->SecondActivity-->返回键-->返回键 <br />
    结果:1)SecondActivity与MainActivity在不同的task中。2)两个SecondActivity为相同的实例 3)第一次返回,会回到MainActivity中 4)第二次返回,会回到MainActivity之前的界面 <br />

    结果分析:1)第一次启动SecondActivity时,由于设置了android:taskAffinity属性,所以会新建一个task并将SecondActivit压入该task中。
    2)第二次启动SecondActivity时,由于SecondActivity已经在当前的task中,所以启动时会将其之上的activity(此处为MainActivity)清理出栈,然后回调SecondActivity的onNewIntent方法。

    SingleTask测试二
    SingleInstance测试一

    在FLAG_ACTIVITY_NEW_TASK测试一的基础上,修改manifest.xml及MainActivity的代码如下

    //AndroidManifest.xml
     <activity android:name=".SecondActivity"
                android:launchMode="singleInstance">
     </activity>
     
     //MainActivity.java
            main_textview.setOnClickListener{
                var intent : Intent = Intent()
                intent.setClass(this, SecondActivity::class.java)
                startActivity(intent)
            }
    

    测试步骤 MainActivity-->SecondActivity-->MainActivity-->SecondActivity<br />
    结果:1)SecondActivity与MainActivity在不同的task中。2)两个SecondActivity为相同的实例 <br />

    SingleInstance.png

    参考链接:

    1. https://juejin.im/post/59b0f25551882538cb1ecae1
    2. https://developer.android.com/guide/topics/manifest/activity-element
    3. https://developer.android.com/guide/components/activities/tasks-and-back-stack
    4. http://wangkuiwu.github.io/2014/06/26/IntentFlag/

    相关文章

      网友评论

          本文标题:Activity四种启动模式及Intent flag

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