Android中一个Activity关闭另一个Activity或者在一个Activity中关闭多个Activity


前言

最近项目中涉及需要在一个Activity中关闭另一个Activity或者在一个Activity中关闭多个Activity的需求,不涉及到应用的退出。自己首先想了一些方案,同时也查了一些方案,就各个方案比较下优劣。


方案一

广播的方式

这个是最容易想到的,同时也是网上提供最多的。
由于多个Activity要使用,关闭页面的广播最好写在基类BaseActivity中,也可以在各个子页面单独写,但是代码量就增加了。

1public class BaseActivity extends Activity { 2 3 //根据需求定义自己需要关闭页面的action 4 public static final String RECEIVER_ACTION_FINISH_A = "receiver_action_finish_a"; 5 public static final String RECEIVER_ACTION_FINISH_B = "receiver_action_finish_b"; 6 public static final String RECEIVER_ACTION_FINISH_C = "receiver_action_finish_c"; 7 public static final String RECEIVER_ACTION_FINISH_D = "receiver_action_finish_d"; 8 9 private FinishActivityRecevier mRecevier; 10 11 @Override 12 protected void onCreate(@Nullable Bundle savedInstanceState) { 13 super.onCreate(savedInstanceState); 14 mRecevier = new FinishActivityRecevier(); 15 registerFinishReciver(); 16 } 17 18 private void registerFinishReciver() { 19 IntentFilter intentFilter = new IntentFilter(); 20 intentFilter.addAction(RECEIVER_ACTION_FINISH_A); 21 intentFilter.addAction(RECEIVER_ACTION_FINISH_B); 22 intentFilter.addAction(RECEIVER_ACTION_FINISH_C); 23 intentFilter.addAction(RECEIVER_ACTION_FINISH_D); 24 registerReceiver(mRecevier, intentFilter); 25 } 26 27 private class FinishActivityRecevier extends BroadcastReceiver { 28 @Override 29 public void onReceive(Context context, Intent intent) { 30 //根据需求添加自己需要关闭页面的action 31 if (RECEIVER_ACTION_FINISH_A.equals(intent.getAction()) || 32 RECEIVER_ACTION_FINISH_B.equals(intent.getAction()) || 33 RECEIVER_ACTION_FINISH_C.equals(intent.getAction()) || 34 RECEIVER_ACTION_FINISH_D.equals(intent.getAction())) { 35 BaseActivity.this.finish(); 36 } 37 } 38 } 39 40 @Override 41 protected void onDestroy() { 42 if (mRecevier != null) { 43 unregisterReceiver(mRecevier); 44 } 45 super.onDestroy(); 46 } 47}

发送广播就需要在各个需求子Activity中进行了,这里使用工具类,方便以后多次或者拓展使用,只需要在需求子Activity中直接调用就行。

1public class BroadcastUtils { 2 /** 3 * 发送finish页面的广播 4 * action可以自己根据需要添加 5 * @param context 6 */ 7 public static void sendFinishActivityBroadcast(Context context) { 8 Intent intent = new Intent(BaseActivity.RECEIVER_ACTION_FINISH_B); 9 context.sendBroadcast(intent); 10 intent = new Intent(BaseActivity.RECEIVER_ACTION_FINISH_C); 11 context.sendBroadcast(intent); 12 } 13}

优劣:
有点:最常规使用,不会出现内存泄漏,在基类中操作,代码量不多。
缺点:项目中若是需要关闭页面多的话,需要发送大量广播,会降低性能。

方案二

直接static activity方式

这是网上提供的,代码一看就明显的内存泄漏。但是。。。。。。

1 private static AActivity sInstance; 2 public static AActivity getInstance() { 3 if (sInstance != null) { 4 return sInstance; 5 } 6 return null; 7 } 8 public static void finishActivity() { 9 if (sInstance != null) { 10 sInstance.finish(); 11 } 12 }

内存泄漏明显,之所以有但是,那是因为这种方式让我想到加入弱引用WeakReference的方式。

1public class BActivity extends BaseActivity { 2 private static WeakReference<BActivity> sActivityRef; 3 4 public static void finishActivity() { 5 if (sActivityRef != null && sActivityRef.get() != null) { 6 sActivityRef.get().finish(); 7 } 8 } 9 @Override 10 protected void onCreate(@Nullable Bundle savedInstanceState) { 11 super.onCreate(savedInstanceState); 12 setContentView(R.layout.activity_b); 13 sActivityRef = new WeakReference<>(this); 14 Button btnB = (Button) findViewById(R.id.btn_b); 15 btnB.setOnClickListener(new View.OnClickListener() { 16 @Override 17 public void onClick(View v) { 18 startActivity(new Intent(BActivity.this, CActivity.class)); 19 } 20 }); 21 } 22 23}

纠结点在于,WeakReference被static之后,里面包裹的引用会被影响吗?查了一下WeakReference以及JVM相关,虽然WeakReference被static了,生命周期变长了,但是WeakReference关联的对象不受影响的,依然遵循WeakReference在gc时候的规则。

优劣:
优点:代码简单直观,引入WeakReference,解决了内存泄漏问题。
缺点:在每个activity中都要添加,代码量多。(不知是否可抽取到积累中,以后尝试)

方案三

使用集合或者栈的方式

这种方式网上很多,但是。。。。。。

1public class FinishActivityManager extends BaseActivity { 2 private FinishActivityManager() { 3 } 4 private static FinishActivityManager sManager; 5 private List<Activity> activityList; 6 public static FinishActivityManager getManager() { 7 if (sManager == null) { 8 synchronized (FinishActivityManager.class) { 9 if (sManager == null) { 10 sManager = new FinishActivityManager(); 11 } 12 } 13 } 14 return sManager; 15 } 16 /** 17 * 添加Activity到集合中 18 */ 19 public void addActivity(Activity activity) { 20 if (activityList == null) { 21 activityList = new LinkedList<>(); 22 } 23 activityList.add(activity); 24 } 25 /** 26 * 关闭指定的Activity 27 */ 28 public void finishActivity(Activity activity) { 29 if (activityList != null && activity != null && activityList.contains(activity)) { 30 //使用迭代器安全删除 31 for (Iterator<Activity> it = activityList.iterator(); it.hasNext(); ) { 32 Activity temp = it.next(); 33 // 清理掉已经释放的activity 34 if (temp == null) { 35 it.remove(); 36 continue; 37 } 38 if (temp == activity) { 39 it.remove(); 40 } 41 } 42 activity.finish(); 43 } 44 } 45 /** 46 * 关闭指定类名的Activity 47 */ 48 public void finishActivity(Class<?> cls) { 49 if (activityList != null) { 50 // 使用迭代器安全删除 51 for (Iterator<Activity> it = activityList.iterator(); it.hasNext(); ) { 52 Activity activity = it.next(); 53 // 清理掉已经释放的activity 54 if (activity == null) { 55 it.remove(); 56 continue; 57 } 58 if (activity.getClass().equals(cls)) { 59 it.remove(); 60 activity.finish(); 61 } 62 } 63 } 64 } 65 /** 66 * 关闭所有的Activity 67 */ 68 public void finishAllActivity() { 69 if (activityList != null) { 70 for (Iterator<Activity> it = activityList.iterator(); it.hasNext(); ) { 71 Activity activity = it.next(); 72 if (activity != null) { 73 activity.finish(); 74 } 75 } 76 activityList.clear(); 77 } 78 } 79 /** 80 * 退出应用程序 81 */ 82 public void exitApp() { 83 try { 84 finishAllActivity(); 85 // 退出JVM,释放所占内存资源,0表示正常退出 86 System.exit(0); 87 // 从系统中kill掉应用程序 88 android.os.Process.killProcess(android.os.Process.myPid()); 89 } catch (Exception e) { 90 e.printStackTrace(); 91 } 92 } 93}

又有但是,这种方式注意在删除的时候使用迭代器,否则会出现并发修改异常。
那就来说说但是,应用中要是不使用这种封装的方式去finish掉Activity的时候,封装的manager并不知道,没有断开并释放掉其引用,会引起内存泄漏。所以WeakReference又要出场了,继续修改吧。

1public class FinishActivityManager extends BaseActivity { 2 private FinishActivityManager() { 3 } 4 private static FinishActivityManager sManager; 5 private Stack<WeakReference<Activity>> mActivityStack; 6 public static FinishActivityManager getManager() { 7 if (sManager == null) { 8 synchronized (FinishActivityManager.class) { 9 if (sManager == null) { 10 sManager = new FinishActivityManager(); 11 } 12 } 13 } 14 return sManager; 15 } 16 /** 17 * 添加Activity到栈 18 * @param activity 19 */ 20 public void addActivity(Activity activity) { 21 if (mActivityStack == null) { 22 mActivityStack = new Stack<>(); 23 } 24 mActivityStack.add(new WeakReference<>(activity)); 25 } 26 27 /** 28 * 检查弱引用是否释放,若释放,则从栈中清理掉该元素 29 */ 30 public void checkWeakReference() { 31 if (mActivityStack != null) { 32 // 使用迭代器进行安全删除 33 for (Iterator<WeakReference<Activity>> it = mActivityStack.iterator(); it.hasNext(); ) { 34 WeakReference<Activity> activityReference = it.next(); 35 Activity temp = activityReference.get(); 36 if (temp == null) { 37 it.remove(); 38 } 39 } 40 } 41 } 42 /** 43 * 获取当前Activity(栈中最后一个压入的) 44 * @return 45 */ 46 public Activity currentActivity() { 47 checkWeakReference(); 48 if (mActivityStack != null && !mActivityStack.isEmpty()) { 49 return mActivityStack.lastElement().get(); 50 } 51 return null; 52 } 53 /** 54 * 关闭当前Activity(栈中最后一个压入的) 55 */ 56 public void finishActivity() { 57 Activity activity = currentActivity(); 58 if (activity != null) { 59 finishActivity(activity); 60 } 61 } 62 /** 63 * 关闭指定的Activity 64 * @param activity 65 */ 66 public void finishActivity(Activity activity) { 67 if (activity != null && mActivityStack != null) { 68 // 使用迭代器进行安全删除 69 for (Iterator<WeakReference<Activity>> it = mActivityStack.iterator(); it.hasNext(); ) { 70 WeakReference<Activity> activityReference = it.next(); 71 Activity temp = activityReference.get(); 72 // 清理掉已经释放的activity 73 if (temp == null) { 74 it.remove(); 75 continue; 76 } 77 if (temp == activity) { 78 it.remove(); 79 } 80 } 81 activity.finish(); 82 } 83 } 84 /** 85 * 关闭指定类名的所有Activity 86 * @param cls 87 */ 88 public void finishActivity(Class<?> cls) { 89 if (mActivityStack != null) { 90 // 使用迭代器进行安全删除 91 for (Iterator<WeakReference<Activity>> it = mActivityStack.iterator(); it.hasNext(); ) { 92 WeakReference<Activity> activityReference = it.next(); 93 Activity activity = activityReference.get(); 94 // 清理掉已经释放的activity 95 if (activity == null) { 96 it.remove(); 97 continue; 98 } 99 if (activity.getClass().equals(cls)) { 100 it.remove(); 101 activity.finish(); 102 } 103 } 104 } 105 } 106 /** 107 * 结束所有Activity 108 */ 109 public void finishAllActivity() { 110 if (mActivityStack != null) { 111 for (WeakReference<Activity> activityReference : mActivityStack) { 112 Activity activity = activityReference.get(); 113 if (activity != null) { 114 activity.finish(); 115 } 116 } 117 mActivityStack.clear(); 118 } 119 } 120 /** 121 * 退出应用程序 122 */ 123 public void exitApp() { 124 try { 125 finishAllActivity(); 126 // 退出JVM,释放所占内存资源,0表示正常退出 127 System.exit(0); 128 // 从系统中kill掉应用程序 129 android.os.Process.killProcess(android.os.Process.myPid()); 130 } catch (Exception e) { 131 e.printStackTrace(); 132 } 133 } 134}

代码一目了然,之所以改成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使用才能达到效果,所以局限性很大。

总结

以上就是几种方案的对比,要是项目中需要关闭Activity不多,不需要发送大量广播,可以使用方案一;方案二和方案三有异曲同工之处,首先推荐方案三。

能力有限,有不对之处,欢迎指出。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

android Activity之间的参数传递

在开发web程序的时候,我们都知道web页面之间是可以传递参数的,在android中,每一个activity就相当于一个页面(窗口),当然,它也是可以传递参数的。思路:通过Intent激活组件(Activity),附带数据Intent(意向):一:通过Intent对象可以激活组件activity,具体有五种方式:方式1:

Android Fragment生命周期

Fragment是在Android3.0中引入,用于解决不同屏幕分辨率的设备上UI显示、交互的问题。Fragment有自己的布局,有自己的生命周期,有自己的事件响应。但Fragment又是依赖于Activity存在的,你可以把多个Fragment嵌入到一个Activity中或者多个Activity重用一个Fragmen

Android Activity生命周期,启动模式,启动过程详解

前言接触过Android开发的同学都知道Activity,Activity作为Android四大组件之一,使用频率高。简单来说Activity提供了一个显示界面,让用户进行各种操作,本文主要分为以下三个部分:Activity的生命周期,启动模式,以及Activity的工作过程。文中大部分篇幅来自《Android开发艺术探索》一书,尽管想多以流程或图

Android 使用intent传递返回值:startActivityForResult()与onActivityResult()与setResult()参数分析,activity带参数的返回

在一个父Activity通过intent跳转至多个不同子Activity上去,当子模块的代码执行完毕后再次返回父页面,将子activity中得到的数据显示在主界面/完成的数据交给父Activity处理。这种带数据的intent跳转需要使用activity的onActivityResult()方法。(1)startActivityForResult(