美文网首页
Handler源码阅读笔记

Handler源码阅读笔记

作者: 橘子树上结西瓜 | 来源:发表于2018-01-15 14:15 被阅读3次

概念

主要用于子线程和主线程(UI线程ActivityThread)通信。【事件驱动模式】
为什么系统不允许子线程更新UI?
(1)UI控件不是线程安全的,多线程并发访问可能会导致UI控件处于不可预期的状态,
(2)虽然加锁可以解决线程安全问题,但是加锁后又两个对手机不可接受的缺点:
   上锁会让UI控件变得复杂和低效;并且会阻塞某些进程的执行.
Handler实现机制
1.Handler发送消息:调用MessageQueue的enqueueMessage()向消息插入到MessageQueue
2.Looper不断轮询调用MessageQueue的next()方法出队(先进先出)
  Looper.loop()轮询消息——>调用messageQueue.next()出队
  ——>调用消息对应的handler来处理消息[msg.target.dispatchMessage(msg)];
  ——>消息对应的handler调用handleMessage()来处理消息.
   Message msg = queue.next(); // might block
   msg.target.dispatchMessage(msg);
3.伪代码
 // 1.handler.sendMessage发送消息
 Message msg =Message.obtain();
 msg.what= MSG_UPDATE_WAY_TWO;
 //handler发送消息的时候会给消息一个标志target(就是一个当前handler对象)
 mHandler.sendMessage(msg);
 
 // 2.Looper.loop()轮询消息,分发消息到指定handler【通过消息的target来判断】
 loop(){
    final Looper me = myLooper();//获取当前线程缓存的looper状态
     if (me == null) {//缓存为空,抛异常
        throw new RuntimeException("No Looper; Looper.prepare() 
        wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue;
    //无限轮询
     for (;;) {
        //调用messageQueue.next()出队消息,获取到消息
        Message msg = queue.next();
        if (msg == null) {//没有消息的时候,轮询结束
            // No message indicates that the message queue is quitting.
            return;
        }
        //通过target【当前出队的msg对应的handler对象】来分发该消息
        msg.target.dispatchMessage(msg);
     }
    //消息处理
    dispathMessage() {//handler的方法
        if (msg.callback != null) {
        //handler构造方法传入的回掉,需要在回掉里重写handleMessage()方法
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
        handleMessage(msg);
    }
}

Handler,Looper,MessageQue三者关系

* 一个线程只能有一个Looper
* 一个Looper只能创建一个MessageQue[Looper.prepare()会创建MessageQueue]
* 多个handler可以绑定一个Looper[可以在Handler构造方法里面传进looper对象]
* ThreadLoacal.set(new Looper(...))存储Looper的状态,
  只有当前线程才能访问.
子线程能直接创建Handler吗? Answer:不能
(1)每个Handler必须绑定一个Looper
【一个线程只能有一个Looper,
一个Looper只能创建一个MessageQue,多个handler可以绑定一个Looper】
(2)子线程创建Handler时,需要在之前调用Looper.prepare()来创建Looper对象;
   主线程在被创建的时候就已经创建了Looper()对象;
   Code:
   new Thread(new Runnable() {
        @Override
        public void run() {
            Looper.prepare();//创建Looper
            handler2 = new Handler(){
                @Override
                public void handleMessage(Message msg) {
                    if (msg.arg1==1) {
                       Toast.makeText(MainActivity.this,"hanlder2",
                       Toast.LENGTH_SHORT).show();
                    }
                    super.handleMessage(msg);
                }
            };
            Message message = handler2.obtainMessage();
            message.arg1 = 1;
            handler2.sendMessage(message);
            Looper.loop();
        }
    }).start();
  或者:new Handler(Looper.getMainLooper());
  直接在Handler构造方法里面传入主线程的Looper对象.
Handler的正确写法(防止内存泄露)
/**
 * Handler正确的使用姿势
 * Created by zk on 2017/10/17.
 */
public class HandlerTestActivity extends AppCompatActivity {

    private final static int TXT_CHANGE=1;
    private final static int IMG_CHANGE=2;

    // ===== Handler作为静态类,避免内存泄露======
    
    // ===== 1.非静态类会持有外部类的引用,而handler的target标记的延迟消息
    发送到messageQue队列中
    
    // ===== 2.Looper会去处理(Handler#handleMessage(Message)),处理消息就是通
    过持有Handler的引用来去处理的
    
    // ===== 3.而Looper的主要工作就是一个一个处理消息队列中的消息对象,主线程
    中的Looper生命周期和当前应用一样长(事件驱动模式)
    
    // ===== 4.这样Looper会长期的持有handler的引用

    private MyHandler myHandler = new MyHandler(this);

    public static class MyHandler extends Handler {

        private final WeakReference<HandlerTestActivity> mActivity;

        public MyHandler(HandlerTestActivity activity){
            mActivity = new WeakReference<HandlerTestActivity>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){//处理handler发送的消息
                case TXT_CHANGE:
                    Log.d("HandlerTestActivity","文本更改");
                    break;
                case IMG_CHANGE:
                    Log.d("HandlerTestActivity","图片更改");
                    break;
            }
        }
    }
    
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //开启子线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //睡眠1秒
                    Thread.sleep(1000);
                    Message msg = new Message();
                    msg.what = TXT_CHANGE;//Message的识别码
                    msg.obj=null;
                    //通过给obj赋值Object类型,向Message传入任意数据
                    //setData()和getData()向Message中写入和读取Bundle类型数据
                    //msg.setData(null);
                    //Bundle data = msg.getData();
                    myHandler.sendMessage(msg);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

相关文章

网友评论

      本文标题:Handler源码阅读笔记

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