1. 程式人生 > >Android複習-任務棧與Activity啟動標記(使用標記啟動Activity時的坑)

Android複習-任務棧與Activity啟動標記(使用標記啟動Activity時的坑)

任務棧,我們說過任務棧的概念,也知道了它的作用,但是在使用過程中會有一些坑。

指定任務棧:

        <activity
            android:name=".Main2Activity"
            android:launchMode="standard"
            android:taskAffinity="com.net.wrf"/>

這個時候就給此Activity指定了它的任務棧,但是它起不起作用還是得具體分析。

比如現在有兩個Activity,A和B,App首先進入A,啟動模式都為standard,並且為B指定taskAffinity屬性,因為不指定的話就預設為應用包名,所以這樣指定了就相當於為B建立一個名為com.net.wrf的任務棧,那麼事實是這樣嗎?

啟動A:

03-13 16:05:24.036 17192-17192/? I/mydata: Main3Activity...onCreate
03-13 16:05:24.036 17192-17192/? I/mydata: Main3Activity..taskId..1630
03-13 16:05:24.037 17192-17192/? I/mydata: Main3Activity...onStart
03-13 16:05:24.037 17192-17192/? I/mydata: Main3Activity...onResume

A啟動B:
03-13 16:05:30.185 17192-17192/ryrj.pzfw.net.activitytest I/mydata: Main3Activity...onPause
03-13 16:05:30.231 17192-17192/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onCreate
03-13 16:05:30.231 17192-17192/ryrj.pzfw.net.activitytest I/mydata: Main2Activity..taskId..1630
03-13 16:05:30.231 17192-17192/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onStart
03-13 16:05:30.232 17192-17192/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onResume
03-13 16:05:30.688 17192-17192/ryrj.pzfw.net.activitytest I/mydata: Main3Activity...onStop

可以發現,B還是進入了A所在的任務棧,那麼taskAffinity沒起作用。

那麼還有一種情況,就是我們不改變上面的配置,A中啟動一個Service,在Serivce內啟動B:

    @Override
    public int onStartCommand(final Intent intent, int flags, int startId) {
        Log.i("mydata","startActivity");
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                Intent intent1 = new Intent(MyIntentService.this,Main2Activity.class);
                intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(intent1);
            }
        },3000);
        return super.onStartCommand(intent, flags, startId);
    }

我們必須加上標記為Intent.FLAG_ACTIVITY_NEW_TASK,否則無論如何都啟動不了。

那麼這種方式啟動的B會發生什麼呢?

03-13 16:08:37.171 19176-19176/ryrj.pzfw.net.activitytest I/mydata: Main3Activity...onCreate
03-13 16:08:37.171 19176-19176/ryrj.pzfw.net.activitytest I/mydata: Main3Activity..taskId..1633
03-13 16:08:37.172 19176-19176/ryrj.pzfw.net.activitytest I/mydata: Main3Activity...onStart
03-13 16:08:37.172 19176-19176/ryrj.pzfw.net.activitytest I/mydata: Main3Activity...onResume

03-13 16:08:57.788 19176-19176/ryrj.pzfw.net.activitytest I/mydata: startActivity

03-13 16:09:00.856 19176-19176/ryrj.pzfw.net.activitytest I/mydata: Main3Activity...onPause
03-13 16:09:00.916 19176-19176/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onCreate
03-13 16:09:00.916 19176-19176/ryrj.pzfw.net.activitytest I/mydata: Main2Activity..taskId..1634
03-13 16:09:00.917 19176-19176/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onStart
03-13 16:09:00.917 19176-19176/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onResume
03-13 16:09:01.639 19176-19176/ryrj.pzfw.net.activitytest I/mydata: Main3Activity...onStop
可以看出,這時任務棧確實不一樣了,如果不指定taskAffinity,那麼在service中啟動的Activity雖然用了標記FLAG_ACTIVITY_NEW_TASK,則無論是standard或者singleTask模式,都會加入到已經存在的那個任務棧中(當然要是非singleInstance任務棧)。

所以總結一下:並不是指定了FLAG_ACTIVITY_NEW_TASK,就要為所啟動的activity建立新的任務棧。

並且Android藝術探索與開發上任主席說FLAG_ACTIVITY_NEW_TASK的作用相當於在XML檔案中指定singleTask模式,我覺得這個是不對的,你不信在一個service中多次使用這個標記啟動一個standard模式的activity,並不會呼叫onNewIntent,會一直重建例項,和singleTask效果並不一樣。有圖有證據:

03-13 16:25:55.495 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main3Activity...onCreate
03-13 16:25:55.496 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main3Activity..taskId..1647
03-13 16:25:55.496 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main3Activity...onStart
03-13 16:25:55.496 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main3Activity...onResume

03-13 16:26:00.962 30665-30665/ryrj.pzfw.net.activitytest I/mydata: startActivity

03-13 16:26:04.008 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main3Activity...onPause
03-13 16:26:04.064 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onCreate
03-13 16:26:04.065 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main2Activity..taskId..1647
03-13 16:26:04.065 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onStart
03-13 16:26:04.066 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onResume
03-13 16:26:04.537 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main3Activity...onStop

03-13 16:26:08.559 30665-30665/ryrj.pzfw.net.activitytest I/mydata: startActivity

03-13 16:26:11.608 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onPause
03-13 16:26:11.651 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onCreate
03-13 16:26:11.651 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main2Activity..taskId..1647
03-13 16:26:11.652 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onStart
03-13 16:26:11.652 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onResume
03-13 16:26:12.117 30665-30665/ryrj.pzfw.net.activitytest I/mydata: Main2Activity...onStop

有人說想要想達到singleTask的效果,必須得用兩個標記位:
                intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);

而Android開發與探索中對FLAG_ACTIVITY_CLEAR_TOP的解釋是,清空它以及它之上的例項,確實是如此,但是並不會回撥onNewIntent方法(因為前面的那個相同Activity例項已經被銷燬了),還是有一點區別的。

在Service中啟動一個Activity如何達到singleTop效果:

                intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);

這個確實可以達到singleTop效果,並且onNewIntent方法也會被回撥。

如何達到一種singleInstance的效果:
                intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

這個確實會保證一個棧中只有一個例項,但是它卻是每次都情況棧,然後建立一個新的例項入棧的,不會複用,也不會呼叫onNewIntent方法。

所以總結:在Service或BoardCastReceiver中啟動Activity時一定要加上FLAG_ACTIVITY_NEW_TASK標記,並且請勿使用諸如CLEAT_TOP或者CLEAT_TASK來達到singleTask或者singleInstance的效果,因為卻是表現一樣,但實質不一樣,還是去XML中指定的為好。

好了,現在來在正常activity中通過標記來啟動activity實驗:

FLAG_ACTIVITY_NEW_TASK : 

場景A加上標記啟動B,不會為B建立新棧,B啟動A,然後再次A啟動B,也不會出現出棧的情況,棧中例項情況為ABAB,所以我覺得它自己使用時沒用。

FLAG_ACTIVITY_CLEAR_TOP:

場景A加上標記啟動B,建立B,B啟動A,建立A,這時是ABA,A再啟動B,則BA出棧,建立一個新的A的入棧。

FLAG_ACTIVITY_CLEAR_TASK:

場景A加上標記啟動B,建立B,B啟動A,然後A再啟動B,沒有任何影響。。

FLAG_ACTIVITY_SINGLE_TOP:

場景A加上標記啟動B,建立B,B啟動A,然後A再啟動B,沒有任何影響。。

總結一下:這些標記單獨使用,只有clearTop是起作用的,其餘的不起作用。

然後我就試了一下上面在service中組合使用的情況下,發現使用Service中的組合情況是有效果的,並且和Service中的效果是一樣的。有人可能會說為什麼在Service中就要使用組合呢,因為Service啟動Activity必須得加上FLAG_ACTIVITY_NEW_TASK,所以實驗的使用實驗其他三種標誌也必須與這個標記組合。

所以,一般情況下不要依賴使用標記,這個產生的效果不是很好。請在配置檔案中配置。