前言
由于一个同学问到我如何按照一个流程走好之后回到首页,我以前看到过4个解决方案,后来发现有做个记录和总结的必要,就写了这篇博文。(之前看小强也写过一篇,这里通过自身的分析完整的总结一下以下6种方案,并加上一个DEMO便于大家了解大体流程)
在Android的用户交互中,按钮触发的意图(Intent)跳转会为你重新打开新的一个界面活动(Activity),对于之前的界面根据需求进行摧毁(Finish())或则保留。
如果一个交互流程中,是从A开始,按照A - B - C - D - A这样的顺序进行的话,那么B,C,D这3个活动界面会根据你D中最后的操作来进行保留或是摧毁,例如
(1)注册流程中,在A界面点击注册,通过B,C,D界面完成注册后,B,C,D就随之摧毁,而如果D中注册不成功没跳转会A的话,那么B,C,D就不能摧毁,之前所填的内容也必须保留。
(2)客户端交互中,返回首页按钮,由于在频繁的点击打开过多的界面(如微信查看朋友圈),返回首页就必须一个一个back回去,所有有的客户端为了优化用户体验,便会加入一个按钮返回首页(之前打开的全部关闭)。
以上几个例子都涉及到了 --- 如何安全退出多个ACTIVITY
其实,这个问题的解决方案有好多种,并且各有各的优缺点,下面就罗列出多个方案以及各个方案的优缺点所在,以便用户根据需求选择。
知识结构
首先,通过大致的思维导图罗列出了以下几个知识点,来帮助你去分析学习:
1.Activity的启动模式
2.intent: Flags属性,以及其显、隐式
3.Application : 全局的使用
4.Activity: onActivityResult(int requestCode, int resultCode, Intent data)方法
5.栈的概念:Last-In/First-Out(LIFO) --- 后进先出的原则
6.BroadcastReceiver 广播
7.栈的引申的知识点:(1)ArrayList和LinkedList的区别 (2)android 栈和队列
以上的 (1)Activity的启动模式 (2)intent: Flags属性 (3)栈的概念
我通过一篇文章写明了他们3者的联系可以点击以下链接查看
Activity启动模式 及 Intent Flags 与 栈 的关联分析
具体方案
方案1
方法:采用FLAG_ACTIVITY_CLEAR_TOP退出整个程序(多activity)
思路:通过Intent的Flags来控制堆栈去解决
android中,每打开一个Activity,便会在栈中加入一个Activity,当该Activity被摧毁后,栈中便移除了它,并且栈中的Activity是按照开打的先后顺序依次排排列的。
Android的窗口类提供了历史栈,我们可以通过stack的原理来巧妙的实现,这里我们在A窗口打开B窗口时在Intent中直接加入标 志 Intent.FLAG_ACTIVITY_CLEAR_TOP,这样开启B时将会清除该进程空间的所有Activity。
代码:
在注册流程最后的FourthStep.class中,点击完成注册点击事件
1. btn_finish.setOnClickListener(new OnClickListener() {
2.
3. @Override
4. public void onClick(View v) {
5. // TODO Auto-generated method stub
6. new Intent(INTENT_METHOD_FIRST_SINGUP);
7. intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
8. startActivity(intent);
9. }
10. });
其中的 INTENT_METHOD_FIRST_SINGUP 是登录界面的Intent隐式Action。
优缺点:
优:使用对栈的巧妙利用,不会赞成内存无故占用等问题,个人认为这个方法是首选。
方案2
方法:通过堆栈管理器去管理
思路:通过堆栈管理器,对Stack进的存储Activity进行操作(推入,推出,弹出)
代码:
1. public class StackManager {
2. /**
3. * Stack 中对应的Activity列表 (也可以写做 Stack<Activity>)
4. */
5. private static Stack mActivityStack;
6. private static StackManager mInstance;
7.
8. /**
9. * @描述 获取栈管理工具
10. * @return ActivityManager
11. */
12. public static StackManager getStackManager() {
13. if (mInstance == null) {
14. new StackManager();
15. }
16. return mInstance;
17. }
18.
19. /**
20. * 推出栈顶Activity
21. */
22. public void popActivity(Activity activity) {
23. if (activity != null) {
24. activity.finish();
25. mActivityStack.remove(activity);
26. null;
27. }
28. }
29.
30. /**
31. * 获得当前栈顶Activity
32. */
33. public Activity currentActivity() {
34. //lastElement()获取最后个子元素,这里是栈顶的Activity
35. if(mActivityStack == null || mActivityStack.size() ==0){
36. return null;
37. }
38. Activity activity = (Activity) mActivityStack.lastElement();
39. return activity;
40. }
41.
42. /**
43. * 将当前Activity推入栈中
44. */
45. public void pushActivity(Activity activity) {
46. if (mActivityStack == null) {
47. new Stack();
48. }
49. mActivityStack.add(activity);
50. }
51.
52. /**
53. * 弹出指定的clsss所在栈顶部的中所有Activity
54. * @clsss : 指定的类
55. */
56. public void popTopActivitys(Class clsss) {
57. while (true) {
58. Activity activity = currentActivity();
59. if (activity == null) {
60. break;
61. }
62. if (activity.getClass().equals(clsss)) {
63. break;
64. }
65. popActivity(activity);
66. }
67. }
68.
69. /**
70. * 弹出栈中所有Activity
71. */
72. public void popAllActivitys() {
73. while (true) {
74. Activity activity = currentActivity();
75. if (activity == null) {
76. break;
77. }
78. popActivity(activity);
79. }
80. }
81. }
之后在注册流程中的对应步骤的Activity的onCreate()中把当前Activity推入栈列表,完成注册流程后,弹出栈列表中流程所涉及的Activity。
优缺点:
缺:如果处理不当,容易造成不在当前界面的Activity被全局引用而摧毁不掉,内存得不到释放,从而无故占用不必要的内存。
方案3:
方法:全局记录打开的Activity或通过一个自定义的类去管理打开的Activity
思路:通过在Application中用一个列表来记录当前所打开的Activity,根据需求去遍历finish()。
描述:和方案2有点类似。
代码:
1. public class AppApplication extends Application {
2. private static AppApplication mAppApplication;
3. /** 当前打开的activity列表 */
4. public ArrayList<Activity> activityList;
5.
6. @Override
7. public void onCreate() {
8. // TODO Auto-generated method stub
9. super.onCreate();
10. this;
11. }
12.
13. /** 获取Application */
14. public static AppApplication getApp() {
15. if (mAppApplication == null) {
16. new AppApplication();
17. }
18. return mAppApplication;
19. }
20.
21. /** 添加当前Activity 到列表中 */
22. public void addActivity(Activity acitivity) {
23. if(activityList == null){
24. new ArrayList<Activity>();
25. }
26. activityList.add(acitivity);
27. }
28.
29. /** 清空列表,取消引用*/
30. public void clearActivity(){
31. activityList.clear();
32. }
33.
34. /** 遍历退出所有Activity */
35. public void exit() {
36. for (Activity activity : activityList) {
37. activity.finish();
38. }
39. //千万记得清空取消引用。
40. 0);
41. }
使用流程和方法2类似。
优缺点:
缺:如果处理不当,容易造成不在当前界面的Activity被全局引用而摧毁不掉,内存得不到释放,从而无故占用不必要的内存。
方案4
方法:使用广播机制解决
思路:通过Activity创建的时候,设置监听广播,在注册流程最后步完成注册时候,发送广播进行遍历finish().
描述:这里我把这些广播的初始化都写在了基类BaseActivity里面,便于维护。
代码:
1. /**
2. * 初始化退出广播
3. */
4. public void initFinishReceiver() {
5. new IntentFilter();
6. filter.addAction(INIENT_FINISH);
7. registerReceiver(mFinishReceiver, filter);
8. }
9.
10. /**
11. * 监听是否退出的广播
12. */
13. public BroadcastReceiver mFinishReceiver = new BroadcastReceiver() {
14.
15. @Override
16. public void onReceive(Context context, Intent intent) {
17. if (INIENT_FINISH.equals(intent.getAction())) {
18. finish();
19. }
20. }
21. };
在流程中的每步Activity中,初始化广播,之后在点击完成注册时候,发送广播
1. btn_finish.setOnClickListener(new OnClickListener() {
2.
3. @Override
4. public void onClick(View v) {
5. // TODO Auto-generated method stub
6. new Intent(INIENT_FINISH));
7. }
8. });
优缺点:
缺:开启过多的广播监听,觉得会浪费资源。
方案5:
方法:通过Activity跳转中传递requestCode的之后根据onActivityResult(int requestCode, int resultCode, Intent data)中返回的resultCode遍历关闭Activity
思路:使用startActivityForResult(intent, requestCode)方法跳转,并且通过
描述:这里我把这些广播的初始化都写在了基类BaseActivity里面便于查看。
代码:
1. /** 关闭时候的requestCode请求码 */
2. public final static int FINISH_REQUESTCODE = 1;
3. /** 关闭时候的resultCode请求码 */
4. public final static int FINISH_RESULTCODE = 1;
5. /**
6. * 方法5通过回调关闭的时候用到
7. */
8. @Override
9. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
10. // TODO Auto-generated method stub
11. if(requestCode == FINISH_REQUESTCODE ){
12. if(resultCode == FINISH_RESULTCODE){
13. setResult(FINISH_RESULTCODE);
14. finish();
15. }
16. }
17. super.onActivityResult(requestCode, resultCode, data);
18. }
之后在流程的Activity中调用带请求码的Intent跳转意图。
1. startActivityForResult(new Intent(getApplicationContext(), SecondStep.class),FINISH_REQUESTCODE);
在最后完成注册流程的时候通过以下方式返回:
1. btn_finish.setOnClickListener(new OnClickListener() {
2.
3. @Override
4. public void onClick(View v) {
5. // TODO Auto-generated method stub
6. setResult(FINISH_RESULTCODE);
7. finish();
8. }
9. });
优缺点:
方案6(不推荐)
方法:方法有人说可以使用抛出异常来退出,可是这样会影响到用户体验,所以不推荐
总结
以上便是我从注册流程分析如何安全退出多个ACTIVITY 的汇总总结,综上所述,博主觉得方案1是最可行的方法,如有什么错误之处,望大家提出,马上改正。
源码DEMO
最后附上源码:下载地址
(以上方式中都已经讲到了对应的方法和代码,源码可以更好的帮助你去体验下这几种方式的使用流程)
标签:DEMO,流程,Activity,Intent,void,activity,new,public From: https://blog.51cto.com/u_16112859/6282448