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,所以實驗的使用實驗其他三種標誌也必須與這個標記組合。
所以,一般情況下不要依賴使用標記,這個產生的效果不是很好。請在配置檔案中配置。