Android--關閉某個指定activity
最近專案中有這樣的需要,在關閉當前Activity同時關閉前面兩個Activity,不涉及到應用的退出。自己想了一些方案,也查了一些資料,做個筆記吧。
方案一
廣播的方式
這個是最容易想到的,同時也是網上提供最多的。 由於多個Activity要使用,關閉頁面的廣播最好寫在基類BaseActivity中,也可以在各個子頁面單獨寫,但是程式碼量就增加了。
public class BaseActivity extends Activity { //根據需求定義自己需要關閉頁面的action public static final String RECEIVER_ACTION_FINISH_A = "receiver_action_finish_a"; public static final String RECEIVER_ACTION_FINISH_B = "receiver_action_finish_b"; public static final String RECEIVER_ACTION_FINISH_C = "receiver_action_finish_c"; public static final String RECEIVER_ACTION_FINISH_D = "receiver_action_finish_d"; private FinishActivityRecevier mRecevier; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mRecevier = new FinishActivityRecevier(); registerFinishReciver(); } private void registerFinishReciver() { IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(RECEIVER_ACTION_FINISH_A); intentFilter.addAction(RECEIVER_ACTION_FINISH_B); intentFilter.addAction(RECEIVER_ACTION_FINISH_C); intentFilter.addAction(RECEIVER_ACTION_FINISH_D); registerReceiver(mRecevier, intentFilter); } private class FinishActivityRecevier extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { //根據需求新增自己需要關閉頁面的action if (RECEIVER_ACTION_FINISH_A.equals(intent.getAction()) || RECEIVER_ACTION_FINISH_B.equals(intent.getAction()) || RECEIVER_ACTION_FINISH_C.equals(intent.getAction()) || RECEIVER_ACTION_FINISH_D.equals(intent.getAction())) { BaseActivity.this.finish(); } } } @Override protected void onDestroy() { if (mRecevier != null) { unregisterReceiver(mRecevier); } super.onDestroy(); } } 複製程式碼
傳送廣播就需要在各個需求子Activity中進行了,這裡使用工具類,方便以後多次或者拓展使用,只需要在需求子Activity中直接呼叫就行。
public class BroadcastUtils { /** * 傳送finish頁面的廣播 * action可以自己根據需要新增 * @param context */ public static void sendFinishActivityBroadcast(Context context) { Intent intent = new Intent(BaseActivity.RECEIVER_ACTION_FINISH_B); context.sendBroadcast(intent); intent = new Intent(BaseActivity.RECEIVER_ACTION_FINISH_C); context.sendBroadcast(intent); } } 複製程式碼
優劣: 有點:最常規使用,不會出現記憶體洩漏,在基類中操作,程式碼量不多。 缺點:專案中若是需要關閉頁面多的話,需要傳送大量廣播,會降低效能。
方案二
直接static activity方式
這是網上提供的,程式碼一看就明顯的記憶體洩漏。但是。。。。。。
private static AActivity sInstance; public static AActivity getInstance() { if (sInstance != null) { return sInstance; } return null; } public static void finishActivity() { if (sInstance != null) { sInstance.finish(); } } 複製程式碼
記憶體洩漏明顯,之所以有但是,那是因為這種方式讓我想到加入弱引用WeakReference的方式。
public class BActivity extends BaseActivity { private static WeakReference<BActivity> sActivityRef; public static void finishActivity() { if (sActivityRef != null && sActivityRef.get() != null) { sActivityRef.get().finish(); } } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_b); sActivityRef = new WeakReference<>(this); Button btnB = (Button) findViewById(R.id.btn_b); btnB.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(BActivity.this, CActivity.class)); } }); } } 複製程式碼
WeakReference以及JVM相關,雖然WeakReference被static了,生命週期變長了,但是WeakReference關聯的物件不受影響的,依然遵循WeakReference在gc時候的規則。 優劣: 優點:程式碼簡單直觀,引入WeakReference,解決了記憶體洩漏問題。 缺點:在每個activity中都要新增,程式碼量多。(不知是否可抽取到基類中,以後嘗試)
方案三
使用集合或者棧的方式
public class FinishActivityManager { private FinishActivityManager() { } private static FinishActivityManager sManager; private List<Activity> activityList; public static FinishActivityManager getManager() { if (sManager == null) { synchronized (FinishActivityManager.class) { if (sManager == null) { sManager = new FinishActivityManager(); } } } return sManager; } /** * 新增Activity到集合中 */ public void addActivity(Activity activity) { if (activityList == null) { activityList = new LinkedList<>(); } activityList.add(activity); } /** * 關閉指定的Activity */ public void finishActivity(Activity activity) { if (activityList != null && activity != null && activityList.contains(activity)) { //使用迭代器安全刪除 for (Iterator<Activity> it = activityList.iterator(); it.hasNext(); ) { Activity temp = it.next(); // 清理掉已經釋放的activity if (temp == null) { it.remove(); continue; } if (temp == activity) { it.remove(); } } activity.finish(); } } /** * 關閉指定類名的Activity */ public void finishActivity(Class<?> cls) { if (activityList != null) { // 使用迭代器安全刪除 for (Iterator<Activity> it = activityList.iterator(); it.hasNext(); ) { Activity activity = it.next(); // 清理掉已經釋放的activity if (activity == null) { it.remove(); continue; } if (activity.getClass().equals(cls)) { it.remove(); activity.finish(); } } } } /** * 關閉所有的Activity */ public void finishAllActivity() { if (activityList != null) { for (Iterator<Activity> it = activityList.iterator(); it.hasNext(); ) { Activity activity = it.next(); if (activity != null) { activity.finish(); } } activityList.clear(); } } /** * 退出應用程式 */ public void exitApp() { try { finishAllActivity(); // 退出JVM,釋放所佔記憶體資源,0表示正常退出 System.exit(0); // 從系統中kill掉應用程式 android.os.Process.killProcess(android.os.Process.myPid()); } catch (Exception e) { e.printStackTrace(); } } } 複製程式碼
這種方式注意在刪除的時候使用迭代器,否則會出現併發修改異常。 那就來說說但是,應用中要是不使用這種封裝的方式去finish掉Activity的時候,封裝的manager並不知道,沒有斷開並釋放掉其引用,會引起記憶體洩漏。所以WeakReference又要出場了。
public class FinishActivityManager { private FinishActivityManager() { } private static FinishActivityManager sManager; private Stack<WeakReference<Activity>> mActivityStack; public static FinishActivityManager getManager() { if (sManager == null) { synchronized (FinishActivityManager.class) { if (sManager == null) { sManager = new FinishActivityManager(); } } } return sManager; } /** * 新增Activity到棧 * @param activity */ public void addActivity(Activity activity) { if (mActivityStack == null) { mActivityStack = new Stack<>(); } mActivityStack.add(new WeakReference<>(activity)); } /** * 檢查弱引用是否釋放,若釋放,則從棧中清理掉該元素 */ public void checkWeakReference() { if (mActivityStack != null) { // 使用迭代器進行安全刪除 for (Iterator<WeakReference<Activity>> it = mActivityStack.iterator(); it.hasNext(); ) { WeakReference<Activity> activityReference = it.next(); Activity temp = activityReference.get(); if (temp == null) { it.remove(); } } } } /** * 獲取當前Activity(棧中最後一個壓入的) * @return */ public Activity currentActivity() { checkWeakReference(); if (mActivityStack != null && !mActivityStack.isEmpty()) { return mActivityStack.lastElement().get(); } return null; } /** * 關閉當前Activity(棧中最後一個壓入的) */ public void finishActivity() { Activity activity = currentActivity(); if (activity != null) { finishActivity(activity); } } /** * 關閉指定的Activity * @param activity */ public void finishActivity(Activity activity) { if (activity != null && mActivityStack != null) { // 使用迭代器進行安全刪除 for (Iterator<WeakReference<Activity>> it = mActivityStack.iterator(); it.hasNext(); ) { WeakReference<Activity> activityReference = it.next(); Activity temp = activityReference.get(); // 清理掉已經釋放的activity if (temp == null) { it.remove(); continue; } if (temp == activity) { it.remove(); } } activity.finish(); } } /** * 關閉指定類名的所有Activity * @param cls */ public void finishActivity(Class<?> cls) { if (mActivityStack != null) { // 使用迭代器進行安全刪除 for (Iterator<WeakReference<Activity>> it = mActivityStack.iterator(); it.hasNext(); ) { WeakReference<Activity> activityReference = it.next(); Activity activity = activityReference.get(); // 清理掉已經釋放的activity if (activity == null) { it.remove(); continue; } if (activity.getClass().equals(cls)) { it.remove(); activity.finish(); } } } } /** * 結束所有Activity */ public void finishAllActivity() { if (mActivityStack != null) { for (WeakReference<Activity> activityReference : mActivityStack) { Activity activity = activityReference.get(); if (activity != null) { activity.finish(); } } mActivityStack.clear(); } } /** * 退出應用程式 */ public void exitApp() { try { finishAllActivity(); // 退出JVM,釋放所佔記憶體資源,0表示正常退出 System.exit(0); // 從系統中kill掉應用程式 android.os.Process.killProcess(android.os.Process.myPid()); } catch (Exception e) { e.printStackTrace(); } } } 複製程式碼
程式碼一目瞭然,之所以改成Stack,是因為要模仿Activity的任務棧的方式,關閉最後開啟的Activity更加方便。 使用的話,在BaseActivity中onCreate()中addActivity,在onDestroy()中finishActivity(),其他功能在各個子Activity中根據需要新增。
優劣: 優點:一勞永逸,一次封裝,方便後續使用。 缺點:暫無。
方案四
使用Activity的launchMode
根據Android啟動模式,standard和singleTop並不能實現專案需求,故排除。
singleTask和singleInstance在使用的時候會和onActivityResult()有點關係: Android 5.0以上的版本能正常使用,沒有衝突; Android 5.0以下的版本有個bug,在呼叫了startActivityForResult之後立馬就會呼叫onActivityResult,不會等到開啟的Activity返回的時候才呼叫。 專案中很多Activity種都有startActivityForResult,故此種方式排除掉。
方案五
使用onActivityResult方式
根據方案四,此方式需要配合launchMode的standard和singleTop使用才能達到效果,所以侷限性很大。