APP定时上锁

模块需求当超过1分钟没有交互的时候,再回到APP需要先跳到九宫格解锁界面进行解锁操作,根据需求可以分析出以下三种情况:

  1. APP从后台回来,超时需要进入解锁;
  2. 手机锁屏、解屏情况;
  3. 手机未锁屏、长时间处于一个界面没有交互的情况;

首先定义一个倒计时器,用来执行倒计时操作:

/**
 * 
 * 倒计时单例工具类
 * 
* * @author hyj * @Date 2016-4-21 下午2:49:21 */ public class BTCCTimer extends CountDownTimer { /** * 倒计时总时长(s) */ private final static long millisInFuture = 5 * 1000; private static BTCCTimer instance; private Activity activity; /** * 倒计时是否结束 */ private static boolean isTimeFinish = false; private BTCCTimer(long millisInFuture, long countDownInterval) { super(millisInFuture, countDownInterval); } /** * 获取一个倒计时实例 * * @return */ public static BTCCTimer getInstance() { if (null == instance) { synchronized (BTCCTimer.class) { if (null == instance) { instance = new BTCCTimer(millisInFuture, 1 * 1000); } } } return instance; } @Override public void onTick(long millisUntilFinished) { BTCLogManager.logE("执行倒计时:" + (millisUntilFinished / 1000) + " " + millisUntilFinished); if (millisUntilFinished <= 2 * 1000) { isTimeFinish = true; return; } isTimeFinish = false; } @Override public void onFinish() { if (isTimeFinish) { BTCLogManager.logE("倒计时解锁,执行锁屏操作"); BaseActivity.CheckPass(activity); isTimeFinish = false; } else { BTCLogManager.logE("倒计时被中断"); } } /** * 显示解锁界面 */ public void showLock(Activity activity) { if (isTimeFinish) { BTCLogManager.logE("跳进解锁界面"); BaseActivity.CheckPass(activity); isTimeFinish = false; } start(activity); } /** * 开始倒计时 * * @param activity */ public void start(Activity activity) { this.activity = activity; stop(); if (activity instanceof CreateGesturePasswordActivity) { BTCLogManager.logE("当前为九宫格解锁界面"); return; } instance.start(); } /** * 停止倒计时 */ public void stop() { instance.cancel(); instance.onFinish(); } }

定义一个屏幕状态监听类,此处屏幕状态监听的主要作用是用于改变我程序中一些变量的值,因为当处于我APP的时候直接关闭屏幕,检测到程序还是在前台运行的。

/**
 * 
 * 
 * 屏幕状态监听
 * 
* * @Date 2016-4-21 下午2:52:36 */ public class ScreenListener { private Context mContext; private ScreenBroadcastReceiver mScreenReceiver; private ScreenStateListener mScreenStateListener; public ScreenListener(Context context) { this.mContext = context; this.mScreenReceiver = new ScreenBroadcastReceiver(); } /** * 开始监听screen状态 * * @param listener */ public void begin(ScreenStateListener listener) { this.mScreenStateListener = listener; registerListener(); getScreenState(); } /** * 获取screen状态 */ private void getScreenState() { if (null == mScreenStateListener) { return; } PowerManager manager = (PowerManager) mContext .getSystemService(Context.POWER_SERVICE); if (manager.isScreenOn()) { mScreenStateListener.onScreenOn(); } else { mScreenStateListener.onScreenOff(); } } /** * 启动screen状态广播接收器 */ private void registerListener() { 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状态监听 */ public void unregisterListener() { mContext.unregisterReceiver(mScreenReceiver); } /** * *
	 * screen状态广播接收者
	 * 
* * @author hyj * @Date 2016-4-20 上午9:36:00 */ private class ScreenBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { switch (intent.getAction()) { case Intent.ACTION_SCREEN_ON:// 开屏 mScreenStateListener.onScreenOn(); break; case Intent.ACTION_SCREEN_OFF: // 锁屏 mScreenStateListener.onScreenOff(); break; case Intent.ACTION_USER_PRESENT:// 解锁 mScreenStateListener.onUserPresent(); break; } } } /** * *
	 * 返回给调用者屏幕状态信息
	 * 
* * @Date 2016-4-20 上午9:34:07 */ public interface ScreenStateListener { /** * 开屏 */ public void onScreenOn(); /** * 锁屏 */ public void onScreenOff(); /** * 解屏 */ public void onUserPresent(); } }

实现一个类继承ActivityLifecycleCallbacks用以捕获activity状态变化:

public class BTCCMWActivityLifecycle implements ActivityLifecycleCallbacks {
	/**
	 * 是否现在退出APP
	 */
	public static boolean isExitAPP = false;
	private int activityCount = 0;// 当前活动Activity的数量
	private Activity preActivity;// 上一个展示界面

	@Override
	public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
		BTCLogManager.logI("运行类名:" + activity.getClass().getSimpleName()
				+ ":onActivityCreated");
	}

	@Override
	public void onActivityStarted(Activity activity) {
		BTCLogManager.logI("运行类名:" + activity.getClass().getSimpleName()
				+ ":onActivityStarted");
		activityCount++;

	}

	@Override
	public void onActivityResumed(Activity activity) {
		BTCLogManager.logI("运行类名:" + activity.getClass().getSimpleName()
				+ ":onActivityResumed");
		preActivity = activity;
		// BTCCTimer.getInstance().showLock();
		BTCCTimer.getInstance().start(preActivity);
	}

	@Override
	public void onActivityPaused(Activity activity) {
		BTCLogManager.logI("运行类名:" + activity.getClass().getSimpleName()
				+ ":onActivityPaused");
	}

	@Override
	public void onActivityStopped(Activity activity) {
		BTCLogManager.logI("运行类名:" + activity.getClass().getSimpleName()
				+ ":onActivityStopped:" + preActivity);
		activityCount--;
		if (activityCount <= 0 && !isExitAPP) {
			BTCLogManager.logI("所有Actvity停止...");
			BTCCTimer.getInstance().start(preActivity);

			if (isBackground(activity)) {
				IPhoneDialogUtil.showToast(activity, "随心用正在后台运行");
				GlobalInfo.homeFlag = true;
				ArgumentBaseActivity.isNoNeedPwd = false;
				BTCCMWApplication.isSettingPassword = false;
			}
		} else {
			BTCCTimer.getInstance().start(preActivity);
		}
	}

	/**
	 * 判断当前应用程序处于前台还是后台
	 */
	public static boolean isApplicationBroughtToBackground(final Context context) {
		ActivityManager am = (ActivityManager) context
				.getSystemService(Context.ACTIVITY_SERVICE);
		List tasks = am.getRunningTasks(1);
		if (!tasks.isEmpty()) {
			ComponentName topActivity = tasks.get(0).topActivity;
			if (!topActivity.getPackageName().equals(context.getPackageName())) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 判断应用是处于后台
	 * 
	 * @param context
	 * @return
	 */
	public static boolean isBackground(Context context) {
		ActivityManager activityManager = (ActivityManager) context
				.getSystemService(Context.ACTIVITY_SERVICE);
		List appProcesses = activityManager
				.getRunningAppProcesses();
		for (RunningAppProcessInfo appProcess : appProcesses) {
			if (appProcess.processName.equals(context.getPackageName())) {
				String msg = "importance = " + appProcess.importance;
				msg += "\nbackground = 400;empty = 500;foreground = 100;";
				msg += "gone = 1000; perceptible = 130;service = 300;visible = 200";
				BTCLogManager.logI(msg);
				if (appProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
					BTCLogManager.logI("检测到在后台运行");
					return true;
				} else {
					BTCLogManager.logI("还在前台1");
					return false;
				}
			}
		}
		BTCLogManager.logI("还在前台2");
		return false;
	}

	@Override
	public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
		BTCLogManager.logI("运行类名:" + activity.getClass().getSimpleName()
				+ ":onActivitySaveInstanceState");
	}

	@Override
	public void onActivityDestroyed(Activity activity) {
		BTCLogManager.logI("运行类名:" + activity.getClass().getSimpleName()
				+ ":onActivityDestroyed");
	}
}

将BTCCMWActivityLifecycle、ScreenListener.ScreenStateListener在Application中onCreate()注册:

registerActivityLifecycleCallbacks(new BTCCMWActivityLifecycle());

// 屏幕状态监听
ScreenListener.ScreenStateListener screenListener = new ScreenListener.ScreenStateListener() {
	@Override
	public void onScreenOn() {
	}

	@Override
	public void onScreenOff() {
		BTCLogManager.logE("屏幕锁定");
		GlobalInfo.homeFlag = true;
		ArgumentBaseActivity.isNoNeedPwd = false;
		BTCCMWApplication.isSettingPassword = false;
	}

	@Override
	public void onUserPresent() {
	}
};
ScreenListener mScreenListener = new ScreenListener(this);
mScreenListener.begin(screenListener);
这些都写完之后,后台运行、锁屏这两种状态下的倒计时都搞定了。

现在就只剩下一种情况了。亮屏的时候长时间无交互需要进入锁屏;当手指点击屏幕的时候需要打断计时,抬起的时候需要重新计时。

这种情况分activity、fragment两种情况

在activity的中,我采用的是在基类BaseActivity中重写dispatchTouchEvent();这种可以覆盖掉Activity的情况

	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		//循环遍历注册过时间的Fragment对象
		for (MyOnTouchListener listener : onTouchListeners) {
			BTCLogManager.logI("循环Fragment:" + ev.getSource());
			listener.onTouch(ev);
		}

		BTCLogManager.logI("dispatchTouchEvent action:" + ev.getAction());
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			BTCLogManager.logI("dispatchTouchEvent 按…………");
			BTCCTimer.getInstance().stop();
			break;

		case MotionEvent.ACTION_UP:
			BTCLogManager.logI("dispatchTouchEvent 松…………");
			BTCCTimer.getInstance().start(this);
			break;
		}


在Fragment中比较麻烦, 采用网友提供的方法,具体做法如下

在BaseActivity中,创建一个回调接口,并向外提供注册、销毁接口,然后在dispatchTouchEvent函数中遍历所有注册了接口的对象,分发onTouchEvent事件。

/**
 * 回调接口
 * @author zhaoxin5
 *
 */
public interface MyTouchListener
{
        public void onTouchEvent(MotionEvent event);
}

/*
 * 保存MyTouchListener接口的列表
 */
private ArrayList myTouchListeners = new ArrayList();

/**
 * 提供给Fragment通过getActivity()方法来注册自己的触摸事件的方法
 * @param listener
 */
public void registerMyTouchListener(MyTouchListener listener)
{
        myTouchListeners.add( listener );
}

/**
 * 提供给Fragment通过getActivity()方法来取消注册自己的触摸事件的方法
 * @param listener
 */
public void unRegisterMyTouchListener(MyTouchListener listener)
{
        myTouchListeners.remove( listener );
}

/**
 * 分发触摸事件给所有注册了MyTouchListener的接口
 */
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
        // TODO Auto-generated method stub 
        for (MyTouchListener listener : myTouchListeners) {
                       listener.onTouchEvent(ev);
        }
        return super.dispatchTouchEvent(ev);
}

然后是在Fragment中的初始化、注册接口,首先需要声明一个父类Activity中的回调接口的对象,然后实现该回调接口中的onTouchEvent方法。并加上自己的处理。

同时需要在该Fragment的初始化函数中,调用父类Activity的registerMyTouchListener函数来注册自己声明的父类Activity中的回调接口的对象,以便把自己加入到父类Activity的事件分发的接收对象列表中。

/**
 * Fragment中,注册
 * 接收MainActivity的Touch回调的对象
 * 重写其中的onTouchEvent函数,并进行该Fragment的逻辑处理
 */
private MainActivity.MyTouchListener mTouchListener = new MyTouchListener() {
        @Override
        public void onTouchEvent(MotionEvent event) {
                // TODO Auto-generated method stub
                if(event.getAction() == MotionEvent.ACTION_UP){
                        //逻辑处理
                }
        }
};

//在该Fragment的构造函数中注册mTouchListener的回调
((MainActivity)this.getActivity()).registerMyTouchListener(mTouchListener);

到这里能覆盖APP定时上锁的大部分场景了。


参考资料:

http://jiawa.net/forum.php?mod=viewthread&tid=405

http://www.daxueit.com/article/10622.html

你可能感兴趣的:(android,后台运行,锁屏监听,亮屏定时)