Handler、Looper、Message学习笔记

 
1、概述

Looper的主要工作是维护一个消息队列,循环地执行以下操作:
(1)从队列中取出消息
(2)将消息交付给Handler处理
(3)回收该消息

Handler的主要工作便是发送消息以及处理消息:
(1)发送消息到消息队列中(入队操作)
(2)处理接收到的消息

Message就不用说了,封装了一些数据,而且还持有对Handler的引用。
 
  
  
2、Looper源码解析:

looper中主要的方法有两个,一个是prepare()方法,一个是loop()方法。

先看prepare()方法,这是Looper的外部入口方法:

private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

 
首先看一下第二行的sThreadLocal,它是ThreadLocal类的实例。

public class ThreadLocal<T> {
    //省略部分代码
    public void set(T value) {
        Thread currentThread = Thread.currentThread();
        Values values = values(currentThread);
        if (values == null) {
            values = initializeValues(currentThread);
        }
        values.put(this, value);
    }
}

可以看到set()方法其实就是将一个对象绑定到了当前线程上,类似的它的get方法则是取出保存的这个对象。

所以prepare方法主要的工作为:
(1)如果已经存在Looper对象,则抛出异常,告诉应用一个线程只能有一个Looper。
(2)如果不存在的话,新建一个Looper对象,然后绑定到当前线程上。

然后来看一下第6行中用到的Looper的构造方法:

private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
}

这是一个私有的构造方法,主要创建了一个消息队列。

最后便是loop()方法了:

public static void loop() {
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue;

    // Make sure the identity of this thread is that of the local process,
    // and keep track of what that identity token actually is.
    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();

    for (;;) {
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }

        // This must be in a local variable, in case a UI event sets the logger
        Printer logging = me.mLogging;
        if (logging != null) {
            logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what);
        }

        msg.target.dispatchMessage(msg);

        if (logging != null) {
            logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
        }

        // Make sure that during the course of dispatching the
        // identity of the thread wasn't corrupted.
        final long newIdent = Binder.clearCallingIdentity();
        if (ident != newIdent) {
            Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
        }

        msg.recycleUnchecked();
    }
}

第2行,又声明了一个me的Looper对象,查看myLooper()方法:

public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

发现me也就是之前在prepare()方法中创建并绑定到当前线程上的那个Looper()对象。

紧接着第6行,又拿到了looper对象中的消息队列(也就是构造方法中创建的那个)。

第13行到44行,便是概述中所说的looper的主要工作了,循环地进行下面操作:
(1)从队列中取出消息: 第三行queue.next()便是从消息队列中取出消息,可能会产生阻塞。
(2)将消息交付给Handler处理:第26行,msg.target就是概述中说的msg对handler的引用,所以此时本质上是handler对消息进行了处理。
(3)回收该消息:第43行对消息进行了回收。

至于代码中的ident相关,推荐阅读:android IPC通信中的UID和PID识别
 
  
  
3、Handler源码解析

首先看一下构造方法Handler()

public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

2-9行是检测Handler是不是有可能导致内存泄露,并且官方推荐使用静态内部类来实现。
第11行再次调用了Looper.myLooper(),拿到了当前线程保存的looper对象,第16行拿到了该looper的messageQueue。

拿到了消息队列,handler自然就有了发送Message的能力,以下全都是sendMessage方法:

public final boolean sendMessage(Message msg){
    return sendMessageDelayed(msg, 0);
}

public final boolean sendEmptyMessage(int what){
    return sendEmptyMessageDelayed(what, 0);
}


public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
    Message msg = Message.obtain();
    msg.what = what;
    return sendMessageDelayed(msg, delayMillis);
}

public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
    Message msg = Message.obtain();
    msg.what = what;
    return sendMessageAtTime(msg, uptimeMillis);
}

public final boolean sendMessageDelayed(Message msg, long delayMillis){
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

可以看到sendMessage最终都是调用了sendMessageAtTime()方法:

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;
    if (queue == null) {
        RuntimeException e = new RuntimeException(
            this + " sendMessageAtTime() called with no mQueue");
        Log.w("Looper", e.getMessage(), e);
    return false;
    }
    return enqueueMessage(queue, msg, uptimeMillis);
}

sendMessageAtTime方法在判断了消息队列不为空后,又调用了enqueueMessage()方法。

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

enqueueMessage方法最终调用了消息队列的入队方法,这样发出的消息终于到了消息队列中。

对了,还记得之前在Looper.loop()方法中,执行了

msg.target.dispatchMessage(msg);

其中的target就是在该方法的第2行进行赋值的,保存了当前handler。
最后一句调用了消息队列的入队方法,将消息发送到了消息队列中。

紧接着就是回调方法dispatchMessage()了,想一想就知道dispatchMessage方法中肯定会涉及到我们重写的handleMessage方法。

 public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

果然在第10行执行了handleMessage(msg)方法,不过很明显执行它是有条件的,即msg.callback、 mCallback均为null。

(1)msg.callback其实是一个runnable对象,当我们在使用handler的post系列的方法时,需要传入一个Runnable对象:

public final boolean post(Runnable r){
    return  sendMessageDelayed(getPostMessage(r), 0);
}

sendMessageDelayed()方法之前写了,传入的是Message对象和延迟时间,所以getPostMessage(r)方法便是将Runnable对象封装成一个Message对象:

private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

该方法的第3行,将runnable对象给了msg的callback属性。
该方法第2行Message.obtain(),源码中的注释解释得很好。如果Message池不为空的话,就取出一个message对象,并将它清空,否则的话创建一个新的Message对象:

/**
 * Return a new Message instance from the global pool. Allows us to
 * avoid allocating new objects in many cases.
 */
public static Message obtain() {
    synchronized (sPoolSync) {
        if (sPool != null) {
            Message m = sPool;
            sPool = m.next;
            m.next = null;
            m.flags = 0; // clear in-use flag
            sPoolSize--;
            return m;
        }
    }
    return new Message();
}

扯了这么多,其实就是想说我们在使用sendMessage(Message msg)方法中,msg.callback默认是为null的。

(2)那么再来看看mCallback
mCallBack是CallBack接口的实例,作为Handler类的成员变量,在构造参数中被初始化:

public interface Callback {
    public boolean handleMessage(Message msg);
}

public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

而我们默认使用的是无参的构造方法时,mCallback默认也是为null的:

public Handler() {
    this(null, false);
}

在dispatchMessage()方法msg.callback、 mCallback均为空时,便会执行handleMessage()方法了,与此同时,福利也来了,这是一个空方法~

/**
 * Subclasses must implement this to receive messages.
 */
public void handleMessage(Message msg) {
}

只有一行注释,子类必须重写这个方法来接收Message对象。
 
 
 
4、一个范例:
说了这么多,也该给一个范例,让身为静态内部类的Handler发出Message后,msg最后能回到自家的handleMessage()手里:
这是一个简单的按钮倒计时操作,点击后按钮开始倒计时60秒,时间到了后又恢复为之前的状态(当然这个功能也可以用CountDownTimer类来实现)。

布局就一个Button就不贴了,下面是Activity的代码:

public class HandlerActivity extends AppCompatActivity {

    private MyHandler mHandler;

    final private static int UPDATE = 1;
    final private static int FINISH = 2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler);

        Button btn = (Button) findViewById(R.id.btnHandler);
        mHandler = new MyHandler(btn);
    }


    static class MyHandler extends Handler {

        private WeakReference<Button> buttonWeakReference;

        MyHandler(Button button) {
            buttonWeakReference = new WeakReference<>(button);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case UPDATE:
                    if (buttonWeakReference.get() != null)
                        buttonWeakReference.get().setText(String.valueOf(msg.arg1));
                    break;
                case FINISH:
                    if (buttonWeakReference.get() != null){
                        buttonWeakReference.get().setClickable(true);
                        buttonWeakReference.get().setText("Button");
                    }
                    break;
                default:
                    break;
            }
        }
    }

    public void onClick(View v) {

        switch (v.getId()){
            case R.id.btnHandler:
                //设置Button不可点击
                v.setClickable(false);
                //启动新线程
                new Thread() {
                    @Override
                    public void run() {

                        for (int i = 60; i > 0; i--) {
                            //发送消息【更新】
                            Message msg = new Message();
                            msg.what = UPDATE;
                            msg.arg1 = i;
                            mHandler.sendMessage(msg);
                            //休眠1s
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        //发送消息【结束】
                        Message msg = new Message();
                        msg.what = FINISH;
                        mHandler.sendMessage(msg);
                    }
                }.start();

                break;
            default:
                break;
        }
    }
}

先写到这里吧。。。


待补充:
1、总结
2、send、post方法
3、messageQueue的实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值