App用戶登入登出設計

App用戶登入登出設計

流程圖

流程圖

注意,登出的時候須要關閉用戶資源。若是不關閉的話,就會致使後臺服務一直接收退出用戶的消息等狀況發生。android

資源

資源

登出

對於APP來講,徹底退出是一項很是基本的功能,可是,這個功能要實現的比較好,也是比較困難的。git

最麻煩的地方就是:**賬號切換了,可是還存在子進程或者子線程在運行上一個用戶業務,致使完成的業務數據寫入當前切換成功的用戶數據庫中。**若是擁有推送進程的話,那麼還須要notify推送進程關閉,避免殺死Service進程又自重啓。數據庫

一般的作法是關閉全部服務,殺死全部的進程,而後重啓。以下是一段比較完善的代碼:app

/**
 * 重啓App
 */
static public void killApp(Context context, boolean restart) {
	//重啓
	if (restart) {
		Intent intent = new Intent(context, MyActivity.class);
		intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		context.startActivity(intent);
	}
  
	//中止後臺 service
	try {
		//讀取全部的SERVICE信息
		PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SERVICES);
		if (packageInfo != null && packageInfo.services != null) {
			for (ServiceInfo serviceInfo : packageInfo.services) {
				try {
					Class cls = Class.forName(serviceInfo.name);
					context.stopService(new Intent(context, cls));
				} catch (ClassNotFoundException e) {
				}
			}
		}
	} catch (Exception e) {
		Log.e(MyActivity.class.getName(), e.getMessage(), e);
	}
	//殺死全部進程
	try {
		Set<String> processNameSet = new HashSet<String>();
		//讀取 全部的Process
		{
			//讀取Activity
			{
				PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES);
				if (packageInfo != null && packageInfo.activities != null) {
					for (ActivityInfo activityInfo : packageInfo.activities) {
						processNameSet.add(activityInfo.processName);
					}
				}
			}
			//讀取Service
			{
				PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SERVICES);
				if (packageInfo != null && packageInfo.services != null) {
					for (ServiceInfo serviceInfo : packageInfo.services) {
						processNameSet.add(serviceInfo.processName);
					}
				}
			}
			//讀取 RECEIVERS
			{
				PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_RECEIVERS);
				if (packageInfo != null && packageInfo.receivers != null) {
					for (ActivityInfo activityInfo : packageInfo.receivers) {
						processNameSet.add(activityInfo.processName);
					}
				}
			}
			//讀取 PROVIDERS
			{
				PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_PROVIDERS);
				if (packageInfo != null && packageInfo.providers != null) {
					for (ProviderInfo providerInfo : packageInfo.providers) {
						processNameSet.add(providerInfo.processName);
					}
				}
			}
		}
		//關閉全部進程
		{
			int myPid = android.os.Process.myPid();
			ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
			Iterator iterator = mActivityManager.getRunningAppProcesses().iterator();
			while (iterator.hasNext()) {
				ActivityManager.RunningAppProcessInfo appProcess = (ActivityManager.RunningAppProcessInfo) iterator.next();
				if (processNameSet.contains(appProcess.processName)) {
					//先KILL其餘進程
					if (appProcess.pid != myPid) {
						android.os.Process.killProcess(appProcess.pid);
					}
				}
			}
			//殺死本身
			android.os.Process.killProcess(myPid);
		}
	} catch (Exception e) {
		Log.e(MyActivity.class.getName(),e.getMessage(),e);
		throw new RuntimeException(e);
	}
}

核心思想是:ide

  1. 發送重啓本身到主Activity事件到AMS
  2. 讀取AndroidManifest.xml 中全部Service信息,調用stopService進行關閉,避免重啓Service
  3. 殺死全部AndroidManifest.xml process 指向的進程,除了本身
  4. 殺死本身

這樣子就能徹底退出app了,值得一提的是網上出現 restartPackage, killBackgroundProcesses 貌似在5.1上都不可行。固然,上面的代碼測試環境,也是5.1了。測試

固然了,體驗比較好的就是依次釋放用戶資源(線程池,數據庫,後臺Service等)。不過該方法實現起來比較困難。.net

總結

在用戶的登入登出設計中,登入的時候須要注意用戶是否以前登入過,而登出設計須要考慮TOKEN失效以及主動退出的問題。而登出設計的時候,還須要考慮關於我的資源(線程池,數據庫,後臺任務等)關閉的問題。線程

參考

相關文章
相關標籤/搜索