在開(kāi)發(fā)中紊选,有時(shí)需要獲取自己APP棧中所有的activity兵罢,比如實(shí)現(xiàn)在某個(gè)activity中徹底退出整個(gè)APP卖词,如果此時(shí)我們能夠獲取到當(dāng)前棧中所有的activity吏夯,那么逐個(gè)finish掉就OK了。當(dāng)然裆赵,要實(shí)現(xiàn)退出整個(gè)APP也不是一定要這么做战授,這只是一種思路而已。
方法1植兰、獲取activity棧(不行)
很多人會(huì)馬上想到通過(guò)獲取系統(tǒng)activity棧的辦法來(lái)實(shí)現(xiàn)瞧甩,相應(yīng)的步驟大概是這樣子的:
//先申請(qǐng)權(quán)限
<uses-permission android:name="android.permission.GET_TASKS" />
//獲取activity任務(wù)棧
ActivityManager activityManager=(ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
//參數(shù)1是指最大任務(wù)棧數(shù)肚逸,一般APP也就只有一個(gè)任務(wù)棧
ActivityManager.RunningTaskInfo runningTaskInfo = activityManager.getRunningTasks(1).get(0);
方法倒是很簡(jiǎn)單朦促,到這里我們就獲取到任務(wù)棧的相關(guān)信息:RunningTaskInfo务冕,然而里面只包含有像什么id啊时甚,頂部activity名字啊离熏,運(yùn)行中activity個(gè)數(shù)等等信息戴涝,而無(wú)法獲取到棧中所有activity實(shí)例啥刻,故無(wú)法達(dá)到目的。
方法2娄涩、基類收集
方法也非常簡(jiǎn)單钝满,我們?cè)谧远x的Application中維護(hù)一個(gè)Activity實(shí)例列表:List<Activity> activitys
然后在activity基類中進(jìn)行收集弯蚜,比如在onCreate中add碎捺,在onDestroy中remove
這樣就可以獲取到棧中所有activity了贷洲,一般這么做簡(jiǎn)單粗暴,貌似也沒(méi)多大問(wèn)題
有的人也許會(huì)擔(dān)心诵叁,如果上面這個(gè)Activity實(shí)例列表中某個(gè)activity被系統(tǒng)回收了拧额,那么如果我們使用它的話豈不是很容易就空指針異常了,其實(shí)這完成可以避免的进栽,比如最簡(jiǎn)單的快毛,你可以在使用前進(jìn)行非空判斷,你也可以使用弱引用唠帝,總之該方法還是具有可行性的没隘。
方法3禁荸、ActivityLifecycleCallbacks收集
上面的方法可行是可行,就是得在基類中進(jìn)行收集瑰妄,如果某個(gè)activity不繼承基類间坐,就收集不了竹宋,而使用ActivityLifecycleCallbacks卻能解決這個(gè)問(wèn)題蜈七,方法也非常簡(jiǎn)單:
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
//可以在這里add
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
//可以在這里remove
}
});
如上面代碼所示飒硅,我們直接在自定義的Application中加入這段代碼即可三娩,這樣我們就得以獲取到Activity相應(yīng)的生命周期雀监,如上面注釋所標(biāo)記的眨唬,我們便可完成activity列表的維護(hù)了会前。
方法4好乐、反射大法
通常來(lái)說(shuō),很多功能的實(shí)現(xiàn)最終總可以通過(guò)發(fā)射來(lái)完成的回官,不然怎么叫做“反射大法”呢!
看過(guò)ActivityThread源碼的都會(huì)注意到里面有這么一個(gè)東東:
final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
沒(méi)錯(cuò)搂橙,它就是系統(tǒng)幫我們收集到的activity集合歉提,下面我們直接上代碼:
public List<Activity> getAllActivitys(){
List<Activity> list=new ArrayList<>();
try {
Class<?> activityThread=Class.forName("android.app.ActivityThread");
Method currentActivityThread=activityThread.getDeclaredMethod("currentActivityThread");
currentActivityThread.setAccessible(true);
//獲取主線程對(duì)象
Object activityThreadObject=currentActivityThread.invoke(null);
Field mActivitiesField = activityThread.getDeclaredField("mActivities");
mActivitiesField.setAccessible(true);
Map<Object,Object> mActivities = (Map<Object,Object>) mActivitiesField.get(activityThreadObject);
for (Map.Entry<Object,Object> entry:mActivities.entrySet()){
Object value = entry.getValue();
Class<?> activityClientRecordClass = value.getClass();
Field activityField = activityClientRecordClass.getDeclaredField("activity");
activityField.setAccessible(true);
Object o = activityField.get(value);
list.add((Activity) o);
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
代碼就是這么簡(jiǎn)單,需要注意一點(diǎn)就是区转,上面ActivityThread中的是ArrayMap苔巨,但我們反射卻只能用Map來(lái)接收,這是因?yàn)锳rrayMap是API 19才引進(jìn)來(lái)的废离,所以我們只能用其父類來(lái)接了侄泽。
另外悼尾,如果你仔細(xì)閱讀了ActivityThread的源碼就會(huì)發(fā)現(xiàn)mActivities收集的邏輯(put)是在onCreate和onStart之后的,所以,如果你在某個(gè)activity的onCreate和onStart調(diào)用上面方法的話泡仗,你將得不到當(dāng)前activity的實(shí)例,而如果你在onResume中調(diào)用的話,則可以獲取到當(dāng)前activity實(shí)例魁巩!