美文网首页
Android的Handler

Android的Handler

作者: 我想吃碗牛肉面 | 来源:发表于2018-08-07 15:21 被阅读20次

    背景

    知其然要知其所以然,为什么会有Handler的出现?举个例子,假设我们在一个Thread中直接刷新某个TextView,并且每毫秒就刷新一次,那么TextView的绘制会疯掉,而且用户体验也不好。所以为了控制UI的刷新频率,Android规定非UI线程不能直接控制UI组件,只能通过Handler来处理。

    概念解析

    非UI线程计算出结果后,将结果封装到Message里,调用Handler对象将消息放到MessageQueue消息队列里,然后由Looper按照自己的节奏从队列中取出消息,交给Handler对象的handleMessage方法处理。


    image.png

    实例化Message
    通常使用Message类里的静态方法obtain(),该方法有多个重载版本可供选择;它的创建并不一定是直接创建一个新的实例,而是先从Message Pool(消息池)中看有没有可用的Message实例,存在则直接取出返回这个实例。如果Message Pool中没有可用的Message实例,则才用给定的参数创建一个Message对象。对于Message对象,一般并不推荐直接使用它的构造方法得到,而是建议通过使用Message.obtain()这个静态的方法或者Handler.obtainMessage()获取。除了上面这种方式,也可以通过Handler对象的obtainMessage()获取一个Message实例。
    [图片上传失败...(image-911b1-1533626470342)]

    Message可以传递什么值
    可以直接赋值一个对象给message.obj,直接赋值个flag给message.what(通常用于区分各个Message),也可以message.setData(bundle),而Bundle对象里可以放各种对象。

    Handler对象发送定义好的Message
    [图片上传失败...(image-e6ba85-1533626470342)]

    通过上图可以看到,
    sendEmptyMessage(int what):直接发送一个flag
    sendEmptyMessageAtTime(int what,long uptimeMillis):指定时间发送
    sendEmptyMessageDelayed(int what,long uptimeMillis):延迟发送
    sendMessageAtFrontOfQueue(Message msg):把消息发到队列前面

    MessageQueue和Looper
    Looper是MessageQueue(消息队列)的管理者。主线程创建时,会创建一个默认的Looper对象,而Looper对象的创建,将自动创建一个MessageQueue。其他非主线程,不会自动创建Looper,要需要的时候,通过调用prepare函数来实现。

    为什么Handler会引起的内存溢出
    1.Android App启动的时候,Android Framework 为主线程创建一个Looper对象,这个Looper对象将贯穿这个App的整个生命周期,它实现了一个消息队列(Message Queue),并且开启一个循环来处理Message对象。而Framework的主要事件都包含着内部Message对象,当这些事件被触发的时候,Message对象会被加到消息队列中执行。
    2.当一个 Handler被实例化时,它将和主线程Looper对象的消息队列相关联,被推到消息队列中的Message对象将持有一个 Handler的引用以便于当Looper处理到这个Message的时候,Framework执行Handler的 handleMessage(Message)方法。
    3.在 Java 语言中,非静态匿名内部类将持有一个对外部类的隐式引用,而静态内部类则不会。

    当 Activity被finish()掉,Message将存在于消息队列中长达10分钟的时间才会被执行到。这个Message持有一个对Handler的引用,Handler也会持有一个对于外部类 (SampleActivity)的隐式引用,这些引用在Message被执行前将一直保持,这样会导致Activity的上下文不被垃圾回收机制回收, 同时也会泄露应用程序的资源(views and resources)。
    在实际开发中,如果内部类的生命周期和Activity的生命周期不一致(比如上面那种,Activity finish()之后要等10分钟,内部类的实例才会执行),则在Activity中要避免使用非静态的内部类,这种情况,就使用一个静态内部类,同时持有一个对Activity的WeakReference。

    使用实例

    //定义该类,使用WeakRefrence是为了防止内存泄露
    private static class MyHandler extends  Handler {
    
            private final WeakReference<OrderProFragment> mFragment;
    
            private MyHandler(OrderProFragment activity) {
                mFragment = new WeakReference<OrderProFragment>(activity);
            }
            @Override
            public void handleMessage(Message msg) {
                OrderProFragment fragment = mFragment.get();
                if(fragment!=null){
                    fragment.handle(msg);
                }
            }
        };
        //定义处理消息方法
        private void handle(Message msg){
            if (msg.what == RUNNING) {
                baseShowLog("mHandler:RUNNING");
            } else if (msg.what == FINISH) {
    
                baseShowLog("mHandler:FINISH");
            }
        }
    

    实例化该内部类:

     MyHandler mMyHandler=new MyHandler(this);
    

    在非UI线程中发送消息

    private void outsideRun(){
        mPayLeftTime--;
        if (mPayLeftTime == 0) {
            mMyHandler.sendEmptyMessage(FINISH);
        } else if (mPayLeftTime > 0) {
            mMyHandler.sendEmptyMessage(RUNNING);
        }
    }
    

    最后别忘了

      @Override
        protected void onDestroy() {
            super.onDestroy();
            if(mMyHandler!=null)mMyHandler.removeCallbacksAndMessages(null);
        }
    

    相关文章

      网友评论

          本文标题:Android的Handler

          本文链接:https://www.haomeiwen.com/subject/ychavftx.html