文档章节

Android 实现App会话超时设计

IamOkay
 IamOkay
发布于 2015/02/01 11:08
字数 748
阅读 4609
收藏 4

这里要考虑3个问题,第一个是锁屏问题,第二个是app被切换至后台的问题,第三个是屏幕锁定和解除时app在后台时的问题


一,监听屏幕解锁,锁定

public class ScreenObserver {

	private static String TAG = "ScreenObserver";
	private Context mContext;
	private ScreenBroadcastReceiver mScreenReceiver;
	private ScreenStateListener mScreenStateListener;
	private static Method mReflectScreenState;

	public ScreenObserver(Context context) {
		mContext = context;
		mScreenReceiver = new ScreenBroadcastReceiver();
		try {
			mReflectScreenState = PowerManager.class.getMethod("isScreenOn",
					new Class[] {});
		} catch (NoSuchMethodException nsme) {
			Log.d(TAG, "API < 7," + nsme);
		}
	}

	/**
	 * screen状态广播接收者
	 * 
	 * @author xishaomin
	 * 
	 */
	private class ScreenBroadcastReceiver extends BroadcastReceiver {
		private String action = null;

		@Override
		public void onReceive(Context context, Intent intent) {
			action = intent.getAction();
			if (Intent.ACTION_SCREEN_ON.equals(action)) {
				mScreenStateListener.onScreenOn();
			} else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
				mScreenStateListener.onScreenOff();
			}else if(Intent.ACTION_USER_PRESENT.equals(action)){
				LogUtils.d("---->屏幕解锁完成");
			}
		}
	}

	/**
	 * 请求screen状态更新
	 * 
	 * @param listener
	 */
	public void requestScreenStateUpdate(ScreenStateListener listener) {
		mScreenStateListener = listener;
		startScreenBroadcastReceiver();

		firstGetScreenState();
	}

	/**
	 * 第一次请求screen状态
	 */
	private void firstGetScreenState() {
		PowerManager manager = (PowerManager) mContext
				.getSystemService(Activity.POWER_SERVICE);
		if (isScreenOn(manager)) {
			if (mScreenStateListener != null) {
				mScreenStateListener.onScreenOn();
			}
		} else {
			if (mScreenStateListener != null) {
				mScreenStateListener.onScreenOff();
			}
		}
	}

	/**
	 * 停止screen状态更新
	 */
	public void stopScreenStateUpdate() {
		mContext.unregisterReceiver(mScreenReceiver);
	}

	/**
	 * 启动screen状态广播接收器
	 */
	private void startScreenBroadcastReceiver() {
		IntentFilter filter = new IntentFilter();
		filter.addAction(Intent.ACTION_SCREEN_ON);
		filter.addAction(Intent.ACTION_SCREEN_OFF);
		//当用户解锁屏幕时
		filter.addAction(Intent.ACTION_USER_PRESENT);
		mContext.registerReceiver(mScreenReceiver, filter);
	}

	/**
	 * screen是否打开状态
	 * 
	 * @param pm
	 * @return
	 */
	private static boolean isScreenOn(PowerManager pm) {
		boolean screenState;
		try {
			screenState = (Boolean) mReflectScreenState.invoke(pm);
		} catch (Exception e) {
			screenState = false;
		}
		return screenState;
	}

	public interface ScreenStateListener {
		public void onScreenOn();

		public void onScreenOff();
	}
	/**
	 * 判断屏幕是否已被锁定
	 * @param c
	 * @return
	 */
	public final static boolean isScreenLocked(Context c) 
	{  
        android.app.KeyguardManager mKeyguardManager = (KeyguardManager) c  
                .getSystemService(Context.KEYGUARD_SERVICE);  
        return mKeyguardManager.inKeyguardRestrictedInputMode();  
    }  
	
	/**
	 * 判断当前应用是否是本应用
	 * @param context
	 * @return
	 */
	public static boolean isApplicationBroughtToBackground(final Context context) {
		ActivityManager am = (ActivityManager) context
				.getSystemService(Context.ACTIVITY_SERVICE);
		List<RunningTaskInfo> tasks = am.getRunningTasks(1);
		if (!tasks.isEmpty()) {
			ComponentName topActivity = tasks.get(0).topActivity;
			if (!topActivity.getPackageName().equals(context.getPackageName())) {
				return true;
			}
		}
		return false;
	}
}

然后在app的BaseActivity中实现ScreenObserver

       private ScreenObservermScreenObserver;
       
       @Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		mScreenObserver = new ScreenObserver(this);
		mScreenObserver.requestScreenStateUpdate(new ScreenStateListener() {
			@Override
			public void onScreenOn() {
				if(!ScreenObserver.isApplicationBroughtToBackground(MainActivity.this))
				{
					cancelAlarmManager();
				}
			}

			@Override
			public void onScreenOff() {
				if(!ScreenObserver.isApplicationBroughtToBackground(MainActivity.this))
				{
					cancelAlarmManager();
					setAlarmManager();
				}
			}
		});
		
	}
		
///此处省略一大坨代码
/**
 * 设置定时器管理器
 */
private void setAlarmManager()
{
	
		long numTimeout = 300*1000;//5分钟
		LogUtils.d("isTimeOutMode=yes,timeout="+numTimeout);
		Intent alarmIntent = new Intent(MainActivity.this, TimeoutService.class);
		alarmIntent.putExtra("action", "timeout"); //自定义参数
		PendingIntent pi = PendingIntent.getService(MainActivity.this, 1024, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
		AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE); 
		long triggerAtTime =  (System.currentTimeMillis()+numTimeout); 
		am.set(AlarmManager.RTC_WAKEUP, triggerAtTime, pi); //设定的一次性闹钟,这里决定是否使用绝对时间
		LogUtils.d("----->设置定时器");
	}
	/**
	 * 取消定时管理器
	 */
	private void cancelAlarmManager()
	{
		AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE); 
		Intent intent = new Intent(MainActivity.this, TimeoutService.class); 
		PendingIntent pi = PendingIntent.getService(MainActivity.this, 1024, intent,PendingIntent.FLAG_UPDATE_CURRENT);
		// 与上面的intent匹配(filterEquals(intent))的闹钟会被取消 
		alarmMgr.cancel(pi);
		LogUtils.d("----->取消定时器");
	}
	
        @Override
	protected void onResume() {
		LogUtils.e("MainActivity-onResume");
		super.onResume();
		cancelAlarmManager();
		activityIsActive = true;
		LogUtils.d("activityIsActive="+activityIsActive);
	}
	
	@Override
	protected void onStop() {
		LogUtils.e("onStop");
		super.onStop();
		if (ScreenObserver.isApplicationBroughtToBackground(this))
		{
		    cancelAlarmManager();
		    setAlarmManager();
		}
	}

然后在后台finishActivity

public class TimeoutService extends Service implements AppConstants {

	@Override
	public IBinder onBind(Intent arg0) {
		return null;
	}

	boolean isrun = true;

	@Override
	public void onCreate() {
		LogUtils.e("BindService-->onCreate()");
		super.onCreate();
	}
	
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		LogUtils.e("BindService-->onStartCommand()");
		forceApplicationExit();
		return super.onStartCommand(intent, flags, startId);
		
	}
	
	private void forceApplicationExit()
	{
		new Thread(new Runnable() {
			@Override
			public void run() {
				ActivityListUtil.getInstence().cleanActivityList();
				stopSelf();
					}
			}).start();
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		isrun = false;
	}

}

ActivityListUtil类如下

public class ActivityListUtil {
	private static ActivityListUtil instence;
	public ArrayList<Activity> activityList;

	public ActivityListUtil() {
		activityList = new ArrayList<Activity>();
	}
	public static ActivityListUtil getInstence() 
	{
		if (instence == null) {
			instence = new ActivityListUtil();
		}
		return instence;
	}
	public void addActivityToList(Activity activity) {
		if(activity!=null)
		{
			activityList.add(activity);
		}
	}
	public void removeActivityFromList(Activity activity)
	{
		if(activityList!=null && activityList.size()>0)
		{
			activityList.remove(activity);
		}
	}
	public void cleanActivityList() {
		if (activityList!=null && activityList.size() > 0) {
			for (int i = 0; i < activityList.size(); i++) {
				Activity activity = activityList.get(i);
				if(activity!=null && !activity.isFinishing())
				{
					activity.finish();
				}
			}
		}
		
	}
}


© 著作权归作者所有

IamOkay

IamOkay

粉丝 204
博文 483
码字总数 403228
作品 0
海淀
程序员
私信 提问
加载中

评论(4)

不忘初心jzy
不忘初心jzy
你好,代码我有点没看懂,能给个demo学习吗?谢谢
温婉柳叶眉
给个demo吧,大神。
2
2015继续拼搏
谢谢!
2
2015继续拼搏
版主 你能把这些方法写成一个demo吗 我有点没看懂0
基于 mmap 的高性能通用 key-value 组件 - MMKV

MMKV——基于 mmap 的高性能通用 key-value 组件 MMKV 是基于 mmap 内存映射的 key-value 组件,底层序列化/反序列化使用 protobuf 实现,性能高,稳定性强。从 2015 年中至今,在 iOS 微信上...

匿名
2018/09/21
946
0
腾讯开源基于 mmap 的高性能 key-value 组件 MMKV

腾讯微信团队宣布开源 MMKV ,这是基于 mmap 内存映射的 key-value 组件,底层序列化/反序列化使用 protobuf 实现,主打高性能和稳定性。MMKV 从 2015 年中至今,在 iOS 微信上使用已有近 3 ...

王练
2018/09/22
3.8K
10
【必看】Android干货整理

哗啦啦,为方便大家更好的学习交流,小编特地整理了一大波干货!预备 前方高能预警,一大波干货袭来,接住了!!!!!!!!!!!! 如果你是零基础小白,不知如何上手Android开发,不知应学习哪些工具...

慕课网官方_运营中心
2018/08/01
0
0
开发一款即时通讯App,从这几步开始

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由腾讯云视频发表于云+社区专栏 关注公众号“腾讯云视频”,一键获取 技术干货 | 优惠活动 | 视频方案 “晚上去哪吃饭啊?”...

腾讯云加社区
2018/10/29
0
0
Android Camera2 预览功能实现

1. 概述 最近在做一些关于人脸识别的项目,需要用到 Android 相机的预览功能。网上查阅相关资料后,发现 Android 5.0 及以后的版本中,原有的 Camera API 已经被 Camera2 API 所取代。 全新的...

Lightweh
2018/11/21
0
0

没有更多内容

加载失败,请刷新页面

加载更多

CentOS 7系统增加swap

转载请注明文章出处:CentOS 7系统增加swap swap是位于磁盘上的特殊文件(或分区),属于“虚拟内存”的一部分。通俗点就是内存的备胎,内存充足的情况下,基本上没swap什么事(和设置有关)...

tlanyan
39分钟前
6
0
基于Prometheus和Grafana的监控平台 - 环境搭建

相关概念 微服务中的监控分根据作用领域分为三大类,Logging,Tracing,Metrics。 Logging - 用于记录离散的事件。例如,应用程序的调试信息或错误信息。它是我们诊断问题的依据。比如我们说...

JAVA日知录
今天
6
0
PHP运行时全局构造体

struct _php_core_globals { zend_bool magic_quotes_gpc; // 是否对输入的GET/POST/Cookie数据使用自动字符串转义。 zend_bool magic_quotes_runtime; //是否对运行时从外部资源产生的数据使...

冻结not
今天
5
0
webpack插件html-webpack-plugin

本文转载于:专业的前端网站→webpack插件html-webpack-plugin 1、插件安装 npm install html-webpack-plugin --save-dev 2、插件使用 webpack.config.js配置文件为: var htmlWebpackPlugin=...

前端老手
今天
7
0
数据挖掘

zhengchen1996
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部