美文网首页
第六章 Handler专题

第六章 Handler专题

作者: 唔笛plk | 来源:发表于2018-12-22 10:12 被阅读0次

一、什么是Handler

由于Android的只允许在UI线程(主线程)中修改UI组件,为了解决其他线程无法改变组件属性值而使用Handler类处理
作用:

  • 在新启动的线程中发送消息
  • 在主线程中获取处理消息

二、Handler的使用

1.post(Runnable)

post方法用于handleMessage()的作用一样处理数据更新UI,源码如下,也是调用sendMessageDelayed方法,省略了很多创建Handler的代码 (适用于处理单一情况)

 /**
     * Causes the Runnable r to be added to the message queue.
     * The runnable will be run on the thread to which this handler is 
     * attached. 
     *  
     * @param r The Runnable that will be executed.
     * 
     * @return Returns true if the Runnable was successfully placed in to the 
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.
     */
    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

2.sendMessage(Message)

sendMessage有多种发送消息的方式,有发送空数据和延迟两个属性,根据具体的情况选择和合适的方式
而且能发送不同类型消息,在handlMessage中处理。(适用于多种情况)

三、Handler内部机制

  • Message:Hanler接收和处理的消息对象。
  • MessageQueue:消息队列,使用FIFO(先进先出)的方式管理Message。创建Loop对象是,也会在构造器中创建MessageQuene对象
 private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
  • Looper:每个线程只能拥有一个Looper,Looper的主要作用是负责读取MessageQueen的Message,读到的Message发送给Handler来处理。
  • Handler:发送和处理消息,Handler正常工作必须在当前线程中拥有一个MessageQueen队列和管理MessageQueen的Looper
  • 在UI线程中已经初始化一个Message和Looper,直接创建Handler即可以处理消息
  • 新的线程中必须Looper.prepare();创建MessageQueen和Looper,然后 Looper.loop();方法启动
new Thread(new Runnable() {
            @Override
            public void run() {
               try {
                        Looper.prepare();
                        sendHandler = new Handler() {
                            @Override
                            public void handleMessage(Message msg) {
                                // TODO
                            }
                        };
                        Looper.loop();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
            }
        }).start();

Looper.loop();的作用是通过死循环的方式不断地从MessageQueen中读取消息

四、Handler引起的内存泄漏以及解决方案

原因:在java中非静态内部类和匿名内部类都会隐式持有当前类的外部引用,由于Handler是非静态内部类所以其持有当前Activity的隐式引用,如果Handler没有被释放,其所持有的外部引用也就是Activity也不可能被释放,因此造成内存泄漏。比如Hander中延迟5min发送消息,在MessaageQueen中队列中持有Hander引用,这队列间接持有Activity引用
解决办法:

  • 使用静态内部类,对Activity进行弱引用
  private static class MyHandler extends Handler{
        //持有弱引用HandlerActivity,GC回收时会被回收掉.
        private final WeakReference<HandlerActivity> mActivty;
        public MyHandler(HandlerActivity activity){
            mActivty =new WeakReference<HandlerActivity>(activity);
        }
        @Override
        public void handleMessage(Message msg) {
            HandlerActivity activity=mActivty.get();
            super.handleMessage(msg);
            if(activity!=null){
                //执行业务逻辑
            }
        }
    }
    private static final Runnable myRunnable = new Runnable() {
        @Override
        public void run() {
            //执行我们的业务逻辑
        }
    };
 
  • 在onDestroy()中,四messageQueenqi清空
    serHandler.removeCallbacksAndMessages(null);

五、如何使用Handler让子线程与子线程之间进行通信

1.创建两个子线程,分别在子线程内创建Hander对象
2.分别在子线程内发送消息

  • 因为Looper.loop()是阻塞线程的因此在loop()之前发送消息
  • 如果构造时不提供Looper类对象参数,会获取当前线程的Looper对象

相关文章

网友评论

      本文标题:第六章 Handler专题

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