阅读源码理解Handler机制

Handler机制作为Android面试重要考点,以前笔者都是参考别的优秀博客来了解,大致能够清楚是怎么一回事。然而在不依赖博客的情况下,就只有自己去阅读源码了。作为Android开发,Android源码就是解决问题的源头泉眼。Handler机制涉及的类比较少,代码量相对于庞大的AMS、WMS那些真是如小菜一碟了。Handler机制真正研究起来不需要花很多的时间,不过卡在某个点这种事情也经常发生。希望笔者写的这一篇可以帮助部分读者打通那些卡住的点。

Handler机制涉及的主要的类有Handler、Looper、MessageQueue和Message。

Handler类

较为常见的是在Activity中声明一个Handler对象出来,这个Handler是主线程的Handler。

public class XXXActivity extends Activity {
	……
	private Handler mHandler = new Handler() {
		@Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            // 处理返回的消息
            if( msg.what == 1 ){
				……
			}
			……
        }
	};
	……
	    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandler.removeCallbacksAndMessages(null);// 防止因Handler引起的内存泄漏
    }
}

Handler的构造方法:

    /**
     * Default constructor associates this handler with the {@link Looper} for the
     * current thread.
     *
     * If this thread does not have a looper, this handler won't be able to receive messages
     * so an exception is thrown.
     */
	// 平时我们在主线程使用的new一个Handler就是使用这个构造
    public Handler() {
        this(null, false);
    }

	public Handler(Callback callback, boolean async){
	……

		mLooper = Looper.myLooper();
		If(mLooper == null){	// 在主线程中不会执行到这里,因为主线程开启时已经绑定了Looper了
			throw new RuntimeException();
		}
		mQueue = mLooper.mQueue;  // Handler的Queue对象与它的Looper对象的mQueue绑定在了一起
		mCallback = callback;
		mAsynchronous = async;
}

主线程开启时Looper被绑定的代码:
ActivityThread:

public static void main(String[] args){
	……
	Looper.prepareMainLooper();//绑定主线程Looper
	……
	Looper.loop();//轮询开始,因为有这句,所以我们在主线程中不需要调用Looper.loop()了,在子线程中实例化Handler对象,需要调用这句话
	throw new RuntimeException(“Main thread loop unexpectedly exited”);
}

来看一下Looper的prepareMainLooper方法和与它相关的方法,loop方法是重头戏,先不那么快讲。
Looper:

    /**
     * Initialize the current thread as a looper, marking it as an
     * application's main looper. The main looper for your application
     * is created by the Android environment, so you should never need
     * to call this function yourself.  See also: {@link #prepare()}
     * 这个方法初始化了应用的main Looper,不应该由开发者调用。调用后通过ThreadLocal的性质将主线程和这个Looper绑定,这个Looper就是主线程的Looper
     */
    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){	// ThreadLocal类中get方法的作用是获取属于当前线程的变量的副本
			throw new RuntimeException("Only one Looper may be created per thread");
		}
		sThreadLocal.set(new Looper(quitAllowed)); // 当前线程和Looper对象绑定在一起,线程为键,Looper对象为值
	}

    /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

    /**
     * Return the {@link MessageQueue} object associated with the current
     * thread.  This must be called from a thread running a Looper, or a
     * NullPointerException will be thrown.
     */
    public static @NonNull MessageQueue myQueue() {
        return myLooper().mQueue;
    }
简单介绍Looper类
  • 持有静态的 ThreadLocal 对象
Static final ThreadLocal< Looper > sThreadLocal = new ThreadLocal< Looper >();

上面代码的注释中解释了一下ThreadLocal存储对象的方式:以线程作为键值来存储对象。它就是Handler机制能在线程中切换的关键因素。因此值得再强调一下。
假设线程1 存储 1,线程2 存储 2,线程3 存储 3……,在线程1使用 ThreadLocal对象取值时(调用sThreadLocal.get()),得到 1,在线程2使用ThreadLocal对象取值时,得到2……。
同理可以推广到对象,假设主线程存储Looper对象0,线程1存储Looper对象1,线程2存储Looper对象2,线程3存储Looper对象3……这样的话我们在主线程就能取到Looper对象0了,与其他线程的Looper对象不产生混淆干扰。

  • 持有MessageQueue对象
    Looper对象一般是通过它的静态方法prepare,每个Looper对象通过构造方法被实例化出来时,会实例化一个MessageQueue对象。MessageQueue是一个消息池,以链表的方式用于存放Message。
private Looper(boolean quitAllowed){
	mQueue = new MessageQueue(quiteAllowed);
	mThread = Thread.currentThread();
}

可以看到,每个Looper对象都有属于它的MessageQueue对象。

  • loop()方法:
public static void 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.Queue;// 主线程的Looper持有的MessageQueue自然也是在主线程中,里面的Message也是主线程的,关键点在于在Handler对象向子线程执行sendMessage方法,Message怎么从子线程跑到主线程了?
	……
	for(;;){
	// 轮询,取出MessageQueue里面的Message对象,next方法是MessageQueue的一个重要方法
		Message msg = queue.next();		// might block
		if( msg == null){
			return null;
		}
	……
	try{
		// 调用Handler的handleMessage()方法,返回一些计算结果的话,可以在主线程做更新UI的操作了
		msg.target.dispatchMessage(msg);
		dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
	} finally{
		……
	}
	}
}
MessageQueue类
Message next(){
	……
	for ( ; ; ){
	……
	synchronized(this)  {
		final long now = SystemClock.uptimeMillis();
		Message prevMsg = null;
		Message msg = mMessage;
		if(msg != null && msg.target == null){ // 还有其它消息要处理
			do{
				prevMsg = msg;
				msg = msg.next; // 链表操作,不断地读取下一个
			}while (msg != null && !msg.isAsynchronous());
		}
		if (msg != null){
			if(now < msg.when){
				nextPollTimeoutMillis = Math.min(msg.when - now, Integer.MAX_VALUE);
		}else{
			mBlocked = false;
			// 链表数据结构,将要处理的Message取出,标记为使用状态,也就是说处理的这个Message被移除出Message的链表了
			if(prevMsg != null){
				prevMsg.next = msg.next;
			}else{
				mMessage = msg.next;
			}
			msg.next = null;
			msg.markInUse();
			return msg;
	}
}
……
}
}
}
sendMessage方法

通过我们会在子线程调用Handler的sendMessage方法来发送消息,在handleMessage方法中处理逻辑,这个sendMessage方法最终会调用到sendMessageAtTime方法:
Handler:

    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;// Handler的MessageQueue对象mQueue就是Looper的MessageQueue对象,Looper的MessageQueue对象与线程绑定,也就是说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);
}

   private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;	// Looper的loop()方法中有 msg.target.dispatchMessage(msg) ,哪个Handler对象发送的消息,返回的结果就由哪个Handler对象来认领处理
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

enqueueMessage方法最终的实现在MessageQueue类中:

boolean enqueueMessage(Message msg, long when) {
        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();// Message标记为使用状态
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {// p == null代表之前没有message
                // New head, wake up the event queue if blocked.
// 链表数据结构,将msg插到最前面
                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机制四个类之间的关系就是这样的了,正所谓篇幅不够代码凑,为了使篇幅不至于太少,同时也使意思达到,笔者尽量在代码中插入注释,使读者阅读源码时,通过提示更能理解源码,最重要的是理解源码。如有不正确的地方,欢迎指出,一起在交流探讨中学习成长。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值