Handler消息机制源码分析

1.什么是Handler

Handler是android中消息机制,Handler运行需要通过MessageQueue和Looper来支撑,Handler主要作用就是将一个任务切换到指定的线程中

2 Handler使用

发送三个消息,通过这三个来分析MessageQueue

public class HandlerActivity extends AppCompatActivity {
    private TextView tv;
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            tv.setText(msg.obj + "");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler);
        tv = findViewById(R.id.tv);
        //开启一个线程发送消息
        new Thread(new Runnable() {
            @Override
            public void run() {
                Message msg1 = Message.obtain();
                msg1.obj = "姚明1";
                mHandler.sendMessage(msg1);

                Message msg2 = Message.obtain();
                msg2.obj = "姚明2";
                mHandler.sendMessageDelayed(msg2,1000);

                Message msg3 = Message.obtain();
                msg3.obj = "姚明3";
                mHandler.sendMessageDelayed(msg3,500);
            }
        }).start();
    }
}

3.MessageQueue消息队列

线程中更新 UI 的时候经常是调用 sendMessage() 和 sendMessageDelayed() ,看一下sendMessage() 方法

	//默认延时时间为0
	public final boolean sendMessage(@NonNull Message msg) {
	  return sendMessageDelayed(msg, 0);
	}
	
	public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
	   return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
	}
	
	public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
	    ...
	    return enqueueMessage(queue, msg, uptimeMillis);
	}
	
	private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
       	//注意这里,msg.target绑定了我们的this也就是Handler
        msg.target = this;
        ....
        return queue.enqueueMessage(msg, uptimeMillis);
    }

3.1MessageQueue的核心代码

	boolean enqueueMessage(Message msg, long when) {

        synchronized (this) {
       		....
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // 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.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

通过上边的这些代码,我们暂时还没有看到 Handler 调用 handleMessage() 方法,但是有了一个重要的结论,我们每次发送一个消息都会被保存到了 MessageQueue 消息队列中,消息队列中采用的是单链表的方式。通过用下面这段代码发送消息,在 MessageQueue 中如图所示。

3.2.MessageQueue内如图所示

	Message msg1 = Message.obtain();
	msg1.obj = "姚明1";
	mHandler.sendMessage(msg1);
	
	Message msg2 = Message.obtain();
	msg2.obj = "姚明2";
	mHandler.sendMessageDelayed(msg2,1000);
	
	Message msg3 = Message.obtain();
	msg3.obj = "姚明3";
	mHandler.sendMessageDelayed(msg3,500);

在这里插入图片描述

3.3 总结

   每次发送一个消息都会添加到消息队列中,按照when时间进行排序,消息队列采用的是单链表形式。

4.Loop消息循环

4.1 子线程中使用Handler

先看一种现象,有时候我们像下面这么写会报错:

	 new Thread(new Runnable() {
            @Override
            public void run() {
            	//子线程中使用Handler
                Handler handler = new Handler();
            }
        }).start();

在这里插入图片描述
必须要这样写

	new Thread(new Runnable() {
		Override
		public void run() {
			//1.创建Looper对象,获取当前线程,通过当前线程获取ThreadLocalMap对象,保证一个线程只有一个Looper对象
			Looper.prepare();
			//2.获取当前的Looper对象,获取当前的MessagerQueue对象
			Handler handler = new Handler();
			//3.发送消息,将消息添加到消息队列中,通过msg.when来进行排序
			Message msg = Message.obtain();
			msg.obj = "姚明"
            handler.sendMessage(msg);
			//4.获取当前的Looper对象,获取当前的MessagerQueue对象,通过死循环不断获取MessageQueue中消息,回掉给Handler的handlerMessage。
			Looper.loop();
		}
	}).start();

我们在主线程中从来没有调用过Looper.prepare();这行代码,为什么就不会报错呢。因为在我们程序入口ActivityThread中的入口函数 main() 已经帮我们调用了这行代码

	public static void main(String[] args) {
      	//....省略部分代码
      	
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

4.2 Looper.prepare()分析

我们来通过看源码来了解Looper.prepare()到底干了什么。

	//静态的
	static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

	public static void prepare() {
        prepare(true);
    }

    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));
    }

	/**
	*  1.获取当前线程,通过当前线程获取线程的ThreadLocalMap对象,一个线程只有一个ThreadLocal对象
	*  2.如果map不为空,就添加,key就是我们的sThreadLocal是静态的,value就是我们的Looper对象。
	*  3.如果map为空就会创建ThreadLocalMap
	*/
	public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

	//创建ThreadLocalMap
	void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

	//创建MessageQueue,获取当前线程。
	 private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
4.2.1 总结

   Looper.prepare() 就是创建了Looper对象,通过当前线程获取ThreadLocalMap,通过set来保证一个线程中只有一个Looper对象

4.3 Looper.loop()解析

	public static void loop() {
		//1.获取当前线程的Looper对象
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        
        //2.获取消息队列
        final MessageQueue queue = me.mQueue;

     	//3.死循环不断获取消息队列中的消息
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            try {
            	//msg.target就是我们的Handler,在MessageQueue中已经提到了msg.target绑定了我们的Handler,可以回去看一下
            	//3.通过 Handler 执行我们Message,这里边就调用我们的handleMessage方法
                msg.target.dispatchMessage(msg);
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
          	//回收我们的消息
            msg.recycleUnchecked();
        }
    }


	/**
     * Handle system messages here.
     */
    public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
            	//4.回掉我们的handleMessage
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值