背景
需求:app在页面无操作,60S后进入休眠页,点击休眠页面再回到上一个页面。
实现
思路:
1、设置全局定时器管理类SleepManager,启动定时器,60S跳转休眠页。
2、监听全局activity的touch事件,重置定时器。
实施
1、创建管理类:
object SleepManager {
private val handler = Handler(Looper.getMainLooper())
private var inactivityTimeout: Long = 60000 // 1 minute in milliseconds
private var reference: WeakReference<Activity>? = null
private val inactivityRunnable = Runnable {
reference?.get()?.let { activity ->
//跳转休眠页面
ScreenSaverActivity.start(activity)
}
}
fun register(app: Application) {
app.registerActivityLifecycleCallbacks(object : CustomActivityCallBack() {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
val window = activity.window
val callback = window.callback
val handler = WindowCallbackInvocation(callback,activity)
val proxy = Proxy.newProxyInstance(
Window.Callback::class.java.classLoader,
arrayOf(Window.Callback::class.java),
handler
) as Window.Callback
window.callback = proxy
}
override fun onActivityPaused(activity: Activity) {
stopInactivityTimer()
}
override fun onActivityResumed(activity: Activity) {
startInactivityTimer(activity)
}
})
}
fun startInactivityTimer(activity: Activity?) {
activity?.let {
reference = WeakReference(activity)
if (activity is ScreenSaverActivity) {
return
}
}
handler.postDelayed(inactivityRunnable, inactivityTimeout)
}
fun stopInactivityTimer() {
handler.removeCallbacks(inactivityRunnable)
}
fun resetInactivityTimer(activity: Activity?) {
handler.removeCallbacks(inactivityRunnable)
startInactivityTimer(activity)
}
}
解释一下:
- register():通过app获取全局activity的生命周期,监听window的touch事件
- 在onActivityPaused移除监听。
- onActivityResumed重新启动监听。
当时想着在baseactivity里重写dispatchTouchEvent,再重置runnable,但是侵入性太强,后面看到有大佬使用动态代理的思路,简单方便。
WindowCallbackInvocation代码如下:
class WindowCallbackInvocation(private val callback: Any, private val activity: Activity) : InvocationHandler {
override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any? {
if ("dispatchTouchEvent" == method?.name) {
val event = args?.firstOrNull() as? MotionEvent
if (MotionEvent.ACTION_UP == event?.action) {
SleepManager.resetInactivityTimer(activity)
}
}
return method?.invoke(callback, *(args ?: arrayOfNulls<Any>(0)))
}
}
原理是:运行时生成代理类WindowCallbackInvocation ,内部拦截Window.Callback的dispatchTouchEvent函数,重置runnable。
好处是还能监听第三方sdk的activity。
使用
在Application中:
class TabletApp : Application() {
override fun onCreate() {
super.onCreate()
SleepManager.register(this)
}
}
不足,目前只能在activity中重置runnable,dialog无效。
解决思路:在dialog show的时候获取window,执行代理逻辑即可。