WeakHandler继续优化

2019-08-06  本文已影响0人  耗子JF

将Handler改成WeakHandler弱引用持有Context以后,新的问题来了,做了延迟操作以后关闭Activity,作为严谨的(强迫症)程序猿,我们还是应该手动去清除handler可能执行的延迟任务Message。有没有办法每次页面生命周期OnPause或者OnDestory的时候自动帮我们完成这个清理呢?这个时候Lifecycle这样的好东西就能帮我们实现这个愿望了!

//重点1:首先记得把WeakHandler继承LifecycleObserver ,这样我们就能观察引用的生命周期了
public class WeakHandler<T extends WeakHandler.WeakHandlerCallBack> extends Handler implements LifecycleObserver {

  //新增一个记录我们发送消息的容器用于回收可能存在的延迟任务
  private Set<Integer> msgList = new HashSet<>();

  public WeakHandler(T t) {
        this.weakReference = new WeakReference<>(t);
        //重点2:在这里设置生命周期观察
        if(weakReference.get() != null && weakReference.get() instanceof LifecycleOwner){
            ((LifecycleOwner) weakReference.get()).getLifecycle().addObserver(this);
        }
    }
  
    /**重点3:通过源码我们发现,所有sendMessage,以及Post任务最终都是通过这个函数发出去的,
      *我们重写这个函数即可记录所有参与发送的延迟任务(为了安全起见,
      *我们把所有发送过得任务都记录下来)
    */
    @Override
    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        /**实际开发中,如果你的项目页面发射的数据比较多(个人感觉不会太多,所有记录了全部数据),
          *可以加上uptimeMillis>0这个过滤条件,另外Post掉的Runner消息也可以采用一样
          *的手段在这里记录,然后再后续移除里进行Remove操作,我就不写了*/
        if(msg != null){
            msgList.add(msg.what);
        }
        return super.sendMessageAtTime(msg, uptimeMillis);
    }

   /**重点4:注册生命周期ON_STOP观察者
      *这样在我们的引用页面调用OnStop的时候我们就能收到信息做remove处理了,很简单吧!
      *同理,有些页面我们不想在OnStop处理,而是需要在OnDestory处理,
      *那我们只需要注册ON_DESTORY然后进行对应的处理就可以了
    */
    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    public void onStop(@NotNull LifecycleOwner owner){
        LogW.i("WeakHandler LifecycleOwner["+owner+"] onStop");
        cleanMsgQuee();
    }

    //这里也能处理Post任务,自行参考这个就可以搞定了
    public synchronized void cleanMsgQuee(){
        if(msgList != null && msgList.size() > 0){
            Iterator<Integer> iterator = msgList.iterator();
            while (iterator.hasNext()) {
                Integer what = iterator.next();
                if(what != null){
                    removeMessages(what);
                    iterator.remove();
                }
                LogW.i("--->>> cleanMsgQuee remove:"+what);
            }
        }
    }
}

整个实现是不是贼简单,hmm,这下可以直接无脑初始化以后调用了,再也不用担心忘记回收Message的问题了!其实这里面还有可以优化的地方,比如重复发送信息如何记录,以及已经完成的任务应该及时去掉,我这里主要提供一个思路,要是有兴趣的可以深入优化一下!

Back:简单好用的解决Handler持有引用导致内存泄漏的方法
上一篇下一篇

猜你喜欢

热点阅读