handler的源码分析

来源:互联网 发布:js中时间格式化字符串 编辑:程序博客网 时间:2024/05/17 01:50

 
package com.linh.handlercodeanalysisl;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.provider.Settings;import android.support.v7.app.AppCompatActivity;import android.widget.TextView;import butterknife.BindView;import butterknife.ButterKnife;public class HandlerCodeAnalysisActivity extends AppCompatActivity {    @BindView(R.id.tv_edit)    TextView tvEdit;    private Handler handler = new Handler(){        @Override        public void handleMessage(Message msg) {            tvEdit.setText((String) msg.obj);        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_handler_code_analysis);        ButterKnife.bind(this);        new Thread(new Runnable() {            @Override            public void run() {                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    e.printStackTrace();                }                Message message1 = Message.obtain();                message1.obj = "这是源码";                handler.sendMessage(message1);                                Message message2 = Message.obtain();                message2.obj = "这是源码分析";                handler.sendMessageDelayed(message2,1000);                                Message message3 = Message.obtain();                message3.obj = "这是源码时间分析";                handler.sendMessageDelayed(message3,500);            }        }).start();    }}//现象,在1000毫秒之后显示的ui由helloworld变成了这是源码分析

MessageQueue消息队列

Handler.sendMessage ->sendMessageDelayed->Message.enqueueMessage
boolean enqueueMessage(Message msg, long when) {        // 判断有没有 target         if (msg.target == null) {            throw new IllegalArgumentException("Message must have a target.");        }        // 有没有在使用         if (msg.isInUse()) {            throw new IllegalStateException(msg + " This message is already in use.");        }        // 对当前消息队列加锁。        synchronized (this) {            // 判断消息队列是否弃用(通常因为线程已死)            if (mQuitting) {                IllegalStateException e = new IllegalStateException(                        msg.target + " sending message to a Handler on a dead thread");                Log.w(TAG, e.getMessage(), e);                msg.recycle();                return false;            }            // 标记消息正在使用中            msg.markInUse();            msg.when = when;            Message p = mMessages;            boolean needWake;            // 第一次添加数据到队列中,或者当前 msg 的时间小于 mMessages 的时间            if (p == null || when == 0 || when < p.when) {                // New head, wake up the event queue if blocked.                // 把当前 msg 添加到链表的第一个                msg.next = p;                mMessages = msg;                needWake = mBlocked;            } else {                // 不是第一次添加数据,并且 msg 的时间 大于 mMessages(头指针) 的时间                // Inserted within the middle of the queue.  Usually we don't have to wake                // up the event queue unless there is a barrier at the head of the queue                // and the message is the earliest asynchronous message in the queue.                needWake = mBlocked && p.target == null && msg.isAsynchronous();                Message prev;                for (;;) {                    // 不断的遍历找到合适的位置                    prev = p;                    p = p.next;                    if (p == null || when < p.when) {                        break;                    }                    if (needWake && p.isAsynchronous()) {                        needWake = false;                    }                }                // 把当前 msg 插入到列表中                msg.next = p; // invariant: p == prev.next                prev.next = msg;            }            // We can assume mPtr != 0 because mQuitting is false.            if (needWake) {                nativeWake(mPtr);            }        }        return true;    }
第一次进来的时候Mseeage  p= null;
msg.next = p--->msg.next = null;
mMessage = msg;


目前为止没有看到handler去调用handleMessage()的方法,目前只是看到messequeue吧消息给了mMessage







总结,handler.sendMeassage其实将message加入到消息队列,队列采用链表的方式,按照when进行时间排序

为什么消息队列要采用链表的方式存储来存储message?

链表的要实现手拉手的数据结构,那么链表中的每一个元素肯定知道他的上一个节点元素和下一个节点元素分别是谁,在java中,弱化了指针的概念,因此,每一个节点元素持有上一个节点元素和下一个节点元素的对象的引用。也就是说,每一个节点对象应该有3个属性:1,value值;  2,上一个节点的引用;  3,下一个节点的引用。这三个属性是链表数据结构的核心,有了这三个属性,基本雏形就已经完成了。接下来,我们在每次添加或者删除或者插入一个新的节点的时候,只需要做2件事情:1,将前一个节点的next引用改变;2,将后一个节点的last引用改变。所以同数组相比,链表增删比较快


Loop消息循环

new Thread(){    @Override    public void run() {        Looper.prepare();        Handler handler = new Handler();        Looper.loop();    }}.start();

子线程中使用handler必须先要调用Looper.prepare()。不然会报错,我们在主线程中并没有调用Loop.prepare()。为什么不报错

因为我们应用启动的时候,activityThread的入口函数main()方法中已经帮我们写了这行代码
Looper.prepareMainLooper()//准备循环
public static void main(String[] args) {    // ... 省略部分代码        Looper.prepareMainLooper();    ActivityThread thread = new ActivityThread();    thread.attach(false);    if (sMainThreadHandler == null) {        sMainThreadHandler = thread.getHandler();    }    Looper.loop();    throw new RuntimeException("Main thread loop unexpectedly exited");}

public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); }}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));}public static @Nullable Looper myLooper() { return sThreadLocal.get();}

sThreadLocal.set(new Looper(quiteAllowed));

 
Thread t = Thread.currentThread();//从线程中获取ThreadLocalMap,一个线程一个ThreadLocalMapThreadLocalMap map = getMap(t);if(map != null){map.set(this,value)}



 总结其实就是保证Thread线程中有且只有一个tlooper对象

这些代码相对就比较简单了,主要还是 ThreadLocal 的 set 方法,用来保证一个线程只有一个 Looper 对象,这样就保证了线程的安全。接下来看一下 Looper.loop() 这行:

public static void loop() {    final Looper me = myLooper();    final MessageQueue queue = me.mQueue;    // 一个死循环    for (;;) {        // 不断的从消息队列里面取消息        Message msg = queue.next(); // might block        if (msg == null) {            // No message indicates that the message queue is quitting.            return;        }        try {            // 通过 target 去 dispatchMessage 而 target 就是绑定的 Handler            msg.target.dispatchMessage(msg);        } finally {            // 消息回收循环利用            msg.recycleUnchecked();        }    }}




原创粉丝点击