一、说明
今天遇到一个需求:
在自定义 View 中会有一个 Timer 定时任务执行更新 UI 操作,希望当页面退出时将定时任务停掉,否则可能由于定时任务无法释放导致内存泄露。
可能有人会建议将在 Activity 的 onDestroy 中停掉定时任务,但这种方式是比较难以维护的,你需要要求每一个用你的自定义 View 的技术人员都记得去释放一下,这不太现实,最好的方式是你的自定义 View 可以自己监听生命周期并进行释放。
二、解决方案
方案 1:将生命周期传入
将 Activity 的所有生命周期传入 View,是最直接也是最笨的一个方法,不到万不得已最好不要这样搞,否则很难维护。
方案 2:用 View 自带的生命周期
android view有以下14个周期:
- onFinishInflate() 当View中所有的子控件均被映射成xml后触发 。
- onMeasure( int , int ) 确定所有子元素的大小 。
- onLayout( boolean , int , int , int , int ) 当View分配所有的子元素的大小和位置时触发 。
- onSizeChanged( int , int , int , int ) 当view的大小发生变化时触发 。
- onDraw(Canvas) view渲染内容的细节。
- onKeyDown( int , KeyEvent) 有按键按下后触发 。
- onKeyUp( int , KeyEvent) 有按键按下后弹起时触发 。
- onTrackballEvent(MotionEvent) 轨迹球事件 。
- onTouchEvent(MotionEvent) 触屏事件 。
- onFocusChanged( boolean , int , Rect) 当View获取或失去焦点时触发 。
- onWindowFocusChanged( boolean ) 当窗口包含的view获取或失去焦点时触发 。
- onAttachedToWindow() 当view被附着到一个窗口时触发 。
- onDetachedFromWindow() 当view离开附着的窗口时触发,对应 onAttachedToWindow()。
- onWindowVisibilityChanged( int ) 当窗口中包含的可见的view发生变化时触发。
比如我想监听退出页面时停止任务,就可以把逻辑写在 onDetachedFromWindow 方法中。
方案 3:为 Activity 添加一个空白自定义 Fragment
这个方案借鉴 Glide 监听生命周期的原理,它会为 Activity 添加一个空白的自定义 Fragment,并在其中监听宿主的生命周期。
具体实现请参考:Glide源码分析3 -- 绑定Activity生命周期