从注冊流程 分析怎样安全退出多个Activity 多种方式(附DEMO)

Posted phlsheji

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从注冊流程 分析怎样安全退出多个Activity 多种方式(附DEMO)相关的知识,希望对你有一定的参考价值。

前言


因为一个同学问到我怎样依照一个流程走好之后回到首页。我曾经看到过4个解决方式,后来发现有做个记录和总结的必要,就写了这篇博文。

(之前看小强也写过一篇,这里通过自身的分析完整的总结一下下面6种方案,并加上一个DEMO便于大家了解大体流程)


android的用户交互中。button触发的意图(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)client交互中。返回首页button,因为在频繁的点击打开过多的界面(如微信查看朋友圈),返回首页就必须一个一个back回去,所有有的client为了优化用户体验,便会增加一个button返回首页(之前打开的所有关闭)。


以上几个样例都涉及到了   ---   怎样安全退出多个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中,点击完毕注冊点击事件

		btn_finish.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				Intent intent = new Intent(INTENT_METHOD_FIRST_SINGUP);
				intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
				startActivity(intent);
			}
		});
当中的 INTENT_METHOD_FIRST_SINGUP 是登录界面的Intent隐式Action。

优缺点:

优:使用对栈的巧妙利用,不会赞成内存无故占用等问题,个人觉得这种方法是首选。


方案2

方法通过堆栈管理器去管理

思路:通过堆栈管理器。对Stack进的存储Activity进行操作(推入。推出,弹出)

代码

public class StackManager {
	/**
	 * Stack 中相应的Activity列表  (也能够写做 Stack<Activity>)
	 */
	private static Stack mActivityStack;
	private static StackManager mInstance;

	/**
	 * @描写叙述 获取栈管理工具
	 * @return ActivityManager
	 */
	public static StackManager getStackManager() {
		if (mInstance == null) {
			mInstance = new StackManager();
		}
		return mInstance;
	}

	/**
	 * 推出栈顶Activity
	 */
	public void popActivity(Activity activity) {
		if (activity != null) {
			activity.finish();
			mActivityStack.remove(activity);
			activity = null;
		}
	}

	/**
	 * 获得当前栈顶Activity
	 */
	public Activity currentActivity() {
		//lastElement()获取最后个子元素,这里是栈顶的Activity
		if(mActivityStack == null || mActivityStack.size() ==0){
			return null;
		}
		Activity activity = (Activity) mActivityStack.lastElement();
		return activity;
	}

	/**
	 * 将当前Activity推入栈中
	 */
	public void pushActivity(Activity activity) {
		if (mActivityStack == null) {
			mActivityStack = new Stack();
		}
		mActivityStack.add(activity);
	}

	/**
	 * 弹出指定的clsss所在栈顶部的中全部Activity
	 * @clsss : 指定的类 
	 */
	public void popTopActivitys(Class clsss) {
		while (true) {
			Activity activity = currentActivity();
			if (activity == null) {
				break;
			}
			if (activity.getClass().equals(clsss)) {
				break;
			}
			popActivity(activity);
		}
	}
	
	/**
	 * 弹出栈中全部Activity
	 */
	public void popAllActivitys() {
		while (true) {
			Activity activity = currentActivity();
			if (activity == null) {
				break;
			}
			popActivity(activity);
		}
	}
}
之后在注冊流程中的相应步骤的Activity的onCreate()中把当前Activity推入栈列表。完毕注冊流程后。弹出栈列表中流程所涉及的Activity。


优缺点

缺:假设处理不当,easy造成不在当前界面的Activity被全局引用而摧毁不掉,内存得不到释放,从而无故占用不必要的内存。


方案3:

方法全局记录打开的Activity或通过一个自己定义的类去管理打开的Activity

思路通过在Application中用一个列表来记录当前所打开的Activity,依据需求去遍历finish()。

描写叙述和方案2有点类似。


代码

public class AppApplication extends Application {
	private static AppApplication mAppApplication;
	/** 当前打开的activity列表 */
	public ArrayList<Activity> activityList;

	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.onCreate();
		mAppApplication = this;
	}

	/** 获取Application */
	public static AppApplication getApp() {
		if (mAppApplication == null) {
			mAppApplication = new AppApplication();
		}
		return mAppApplication;
	}

	/** 加入当前Activity 到列表中 */
	public void addActivity(Activity acitivity) {
		if(activityList == null){
			activityList = new ArrayList<Activity>();
		}
		activityList.add(acitivity);
	}
	
	/** 清空列表,取消引用*/
	public void clearActivity(){
		activityList.clear();
	}

	/** 遍历退出全部Activity */
	public void exit() {
		for (Activity activity : activityList) {
			activity.finish();
		}
		clearActivity();//千万记得清空取消引用。
		System.exit(0);
	}
使用流程和方法2类似。

优缺点

缺:假设处理不当,easy造成不在当前界面的Activity被全局引用而摧毁不掉,内存得不到释放,从而无故占用不必要的内存。


方案4

方法使用广播机制解决

思路:通过Activity创建的时候,设置监听广播,在注冊流程最后步完毕注冊时候,发送广播进行遍历finish().

描写叙述这里我把这些广播的初始化都写在了基类BaseActivity里面。便于维护。

代码

	/**
	 * 初始化退出广播
	 */
	public void initFinishReceiver() {
		IntentFilter filter = new IntentFilter();
		filter.addAction(INIENT_FINISH);
		registerReceiver(mFinishReceiver, filter);
	}
	
	/**
	 * 监听是否退出的广播
	 */
	public BroadcastReceiver mFinishReceiver = new BroadcastReceiver() {

		@Override
		public void onReceive(Context context, Intent intent) {
			if (INIENT_FINISH.equals(intent.getAction())) {
				finish();
			}
		}
	};
在流程中的每步Activity中,初始化广播。之后在点击完毕注冊时候,发送广播
		btn_finish.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				getApplicationContext().sendBroadcast(new Intent(INIENT_FINISH));
			}
		});
优缺点

缺:开启过多的广播监听,认为会浪费资源。


方案5:

方法通过Activity跳转中传递requestCode的之后依据onActivityResult(int requestCode, int resultCode, Intent data)中返回的resultCode遍历关闭Activity

思路使用startActivityForResult(intent, requestCode)方法跳转,而且通过

描写叙述:这里我把这些广播的初始化都写在了基类BaseActivity里面便于查看。

代码

/** 关闭时候的requestCode请求码 */
	public final static int FINISH_REQUESTCODE = 1;
	/** 关闭时候的resultCode请求码 */
	public final static int FINISH_RESULTCODE = 1;
	/**
	 * 方法5通过回调关闭的时候用到
	 */
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		// TODO Auto-generated method stub
		if(requestCode == FINISH_REQUESTCODE ){
			if(resultCode == FINISH_RESULTCODE){
				setResult(FINISH_RESULTCODE);
				finish();
			}
		}
		super.onActivityResult(requestCode, resultCode, data);
	}
之后在流程的Activity中调用带请求码的Intent跳转意图。

startActivityForResult(new Intent(getApplicationContext(), SecondStep.class),FINISH_REQUESTCODE);
在最后完毕注冊流程的时候通过下面方式返回:
	btn_finish.setOnClickListener(new OnClickListener() {

		@Override
		public void onClick(View v) {
			// TODO Auto-generated method stub
			setResult(FINISH_RESULTCODE);
			finish();
		}
	});

优缺点

方案6(不推荐)

方法方法有人说能够使用抛出异常来退出,但是这样会影响到用户体验。所以不推荐



总结

以上便是我从注冊流程分析怎样安全退出多个ACTIVITY 的汇总总结。综上所述,博主认为方案1是最可行的方法,如有什么错误之处,望大家提出。立即改正。


源代码DEMO

技术分享


最后附上源代码:下载地址   

(以上方式中都已经讲到了相应的方法和代码,源代码能够更好的帮助你去体验下这几种方式的使用流程)








































以上是关于从注冊流程 分析怎样安全退出多个Activity 多种方式(附DEMO)的主要内容,如果未能解决你的问题,请参考以下文章

谈谈移动互联网应用的用户注冊登录安全考虑之不可逆加密的应用原则

怎样注冊一个微信公众号

Android笔记——Activity中的数据传递案例(用户注冊)

android怎样点击两下退出程序

退出多个activity的方法

使用广播退出多个activity