源码分析 — Handler机制(线程间通信)

一、前言

线程间通讯机制的内部实现原理,即HandlerMessageMessageQueueLooperHandlerThreadAsyncTask类的实现以及之间的关系。


二、了解相关的几个类:

  • Handler:负责发送Message和Runnable到MessageQueue中,然后依次处理MessageQueue队列里的消息。
  • MessageQueue:消息队列。负责存放一个线程的Message和Runnable的集合。
  • Message:消息实体类。
  • Looper:消息轮询器。负责将MessageQueue中的Message或Runnable循环取出来,然后分发到Handler中。
小结:
  1. 这四者的关系:
    • 一个线程可以有多个Handler实例,
    • 一个线程只能有一个Looper和MessageQueue,
    • 一个MessageQueue对应多个Message和Runnable。
  2. 一对多的关系:
    • 一方:Looper和MessageQueue
    • 多方:Handler、Message和Runnable

三、主线程和子线程之间的通信

3.1 Handler类

当实例化一个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.
 */
public Handler() {
    this(null, false);
}

public Handler(Callback callback, boolean async) {

      ······
    //获取Looper对象
    mLooper = Looper.myLooper();
      ······
    //获取消息队列实体
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

问题: 为什么说一个线程对应一个Looper实例?

分析: 查看Looper.myLooper()源码

//-------------------ThreadLacal类----------------------

// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); 
/**
 * Return the Looper object associated with the current thread.  Returns
 * null if the calling thread is not associated with a Looper.
 */
public static Looper myLooper() {
    return sThreadLocal.get();//获得当前线程的Looper实例。
}

3.2 ThreadLocal类

这个类实现了一个线程的本地存储,即每个线程都会有自己的内存空间来存放线程自己的值。
同时,所有的线程都共享一个ThreadLocal对象,但是不同的线程会有对应不同的value,且单独修改某一个线程值时不影响其它线程值,并支持null值。

小结: 每个线程都会存放一个独立的Looper实例,通过ThreadLocal.get()方法,就会获得当前线程的Looper实例。


问题: Handler是如何发生Runnable的呢?
分析:

//-------------------Handler类-------------------
public final boolean post(Runnable r) {
    return  sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;  //将Runnable对象当作msg中的callback属性传入;
    return m;
}

小结: 其实传入的Runnable对象都是封装到Message类中。


问题: 那么Message中存放哪些信息呢?
分析: Message.obtain()是获取断掉的Message链关系的第一个Message。

  1. Message.obtain()是通过从全局Message sPool中读取一个Message,回收的时候也是将Message放入到mPool中。
  2. Message中实现了Parcelable接口。
public final class Message implements Parcelable {   
    public int what;
    public int arg1; 
    public int arg2;
    public Object obj;
    public Messenger replyTo;
    static final int FLAG_IN_USE = 1 << 0;
    static final int FLAG_ASYNCHRONOUS = 1 << 1;
    static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;
    int flags;
    long when;  //向Handler发送Message生成的时间
    Bundle data;   //在Bundler对象上绑定要在线程中传递的数据
    Handler target;   //处理当前Message的Handler对象
    Runnable callback;   
    Message next;   //当前Message对下一个Message的引用
    private static final Object sPoolSync = new Object();
    private static Message sPool;   //有下一个Message引用的Message链(Message池)
    private static int sPoolSize = 0;
    private static final int MAX_POOL_SIZE = 50;
    /**
     * 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;
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }
}

问题: Handler是如何发生Message的呢?
分析:

//-------------------------Handler类----------------------------

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

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

小结: 当按时间发送时,无论是发送Message还是Runnable,最终调用的都是sendMessageAtTime()方法,里面的核心方法是enqueueMessage()方法,该方法就是调用MessageQueue中的enqueueMessage()方法,其实就是将Message加入到消息队列中。


问题: 如果发送消息只是将消息加入到消息队列中,那谁来把消息分发到Handler中呢?
分析:

//------------------------Looper类---------------------------
/**
 * Run the message queue in this thread. Be sure to call
 * {@link #quit()} to end the loop.
 */
public static void loop() {
    //获取一个Looper对象
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    //获取Looper里的消息队列
    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);
        }
        
        //消息分发 handler.dispatchMessage(msg),将消息从轮询器中取出发送到对应的handler中
        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.recycle();//释放消息占据的资源
    }
}

//----------------------Handler类---------------------------
/**
 * Handle system messages here.
 */
public void dispatchMessage(Message msg) {
    //msg.callback其实就是传入的Runnable对象;
    if (msg.callback != null) {
        //如果handler传入的值是Runnable,则直接执行callback回调
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        //Callback接口,具体业务处理在这里执行
        handleMessage(msg);
    }
}

小结:
在Looper类的loop()方法中调用Handler的dispatchMessage(msg)方法,在dispatchMessage(msg)内部最终调用了handlerMessage(msg)。
换句话说,Looper.loop()方法就是取得当前线程中的MessageQueue实例,然后不断循环获取消息,并将消息分发到对应的Handler实例上。
实质上只要调用Looper.loop()方法,就可以执行消息分发。

四、Handler、Message、MessageQueue、Looper的关系原理图:

这里写图片描述

整个机制实现原理流程:
当应用程序运行时,会创建一个Linux进程和一个UI线程(ActivityThread),这个类里有一个main方法,是Java程序运行最开始的入口。

//-----------------------ActivityThread类---------------------------
public static void main(String[] args) {  
    SamplingProfilerIntegration.start();  
  
    // CloseGuard defaults to true and can be quite spammy.  We  
    // disable it here, but selectively enable it later (via  
    // StrictMode) on debug builds, but using DropBox, not logs.  
    CloseGuard.setEnabled(false);  
  
    Process.setArgV0("<pre‐initialized>");  
  
    //由framework设置的UI程序的主消息循环,注意,这个主消息循环是不会主动退出的
    Looper.prepareMainLooper();  
    if (sMainThreadHandler == null) {  
        sMainThreadHandler = new Handler();  
    }  
    //创建主线程
    ActivityThread thread = new ActivityThread();  
    thread.attach(false);  
  
    if (false) {  
        Looper.myLooper().setMessageLogging(new  
        LogPrinter(Log.DEBUG, "ActivityThread"));  
    }  
    //获取MessageQueue实例,执行消息分发
    Looper.loop()
  
    throw new RuntimeException("Main thread loop unexpectedly exited");  
}  

ActivityThread() {
	...省略代码...
}

小结: UI线程一执行就已经调用了loop消息分发,所以当在UI线程中通过Handler对象发送消息或者任务时,会把Message加入到MessageQueue消息队列中,然后分发到Handler的handlerMessage方法里。


五、子线程之间的线程通信

问题: 如何实现子线程之间的线程通信?
分析: 其实就是在子线程中实现handler.handleMessage()方法的调用。

//----------------------Thread类----------------------------
public Thread(String threadName) {
    if (threadName == null) {
        throw new NullPointerException("threadName == null");
    }
	//创建一个子线程
    create(null, null, threadName, 0);
}

//--------------------------HandlerThread类-------------------------------
/**
 * Handy class for starting a new thread that has a looper. The looper can then be 
 * used to create handler classes. Note that start() must still be called.
 */
public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;
    public HandlerThread(String name) {
        super(name); //调用Thread(String threadName)
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    
    /**
     * Constructs a HandlerThread.
     * @param name
     * @param priority The priority to run the thread at. The value supplied must be from 
     * {@link android.os.Process} and not from java.lang.Thread.
     */
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
    
    /**
     * Call back method that can be explicitly overridden if needed to execute some
     * setup before Looper loops.
     */
    protected void onLooperPrepared() {
    }
    @Override
    public void run() {
        mTid = Process.myTid();
		
		//Initialize the current thread as a looper.
        Looper.prepare();
        synchronized (this) {
			//实例化Looper对象
            mLooper = Looper.myLooper();
            notifyAll();//Object类中的本地方法(native)
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();

		//内部实现消息分发功能
        Looper.loop();
        mTid = -1;
    }
    
    /**
     * This method returns the Looper associated with this thread. If this thread not been started
     * or for any reason is isAlive() returns false, this method will return null. If this thread 
     * has been started, this method will block until the looper has been initialized.  
     * @return The looper.
     */
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }
    /**
     * Quits the handler thread's looper.
     * @return True if the looper looper has been asked to quit or false if the
     * thread had not yet started running.
     * @see #quitSafely
     */
    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }
    /**
     * Quits the handler thread's looper safely.
     * @return True if the looper looper has been asked to quit or false if the
     * thread had not yet started running.
     */
    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }
    /**
     * Returns the identifier of this thread. See Process.myTid().
     */
    public int getThreadId() {
        return mTid;
    }
}

小结: 通过查看HandlerThread源码,发现HandlerThread继承自Thread类,从run()方法中可以发现,HandlerThread要调用start()方法,才能实例化HandlerThread的Looper对象和实现消息分发功能。
所以,要使用HandlerThread,必须先运行HandlerThread,这样才能取出对应的Looper对象,然后使用Handler(Looper)构造方法实例化Handler(即实现Handler和Looper的关联),这时handler就可以再子线程中执行handlerMessage()方法了。


HandlerThread类

自身继承Thread,是一个子线程;
与Handler+Message+Thread的区别:HandlerThread类里面处理Message消息可以是耗时操作,但是不能对UI操作,即handleMessage()方法只能在子线程中执行;
例子:

public void onCreate(Bundle savedInstanceState) {  
    super.onCreate(savedInstanceState);  
    
    HandlerThread mThread = new HandlerThread("myThread");  
    //先调用start(启动一个线程
    mThread.start();  
    //调用Handler(Looper)方法实例化一个Handler对象
    myHandler myHandler = new myHandler(mThread.getLooper());     
    Message msg = myHandler.obtainMessage();  
    //把Message发送到目标对象,目标对象就是生成msg的目标对象。
    msg.sendToTarget();  //实际上方法内部调用handler.sendMessage(msg);
}  
 
class myHandler extends Handler {  
    //必须调用Handler(Looper looper)方法  
    public myHandler(Looper looper) {  
        super(looper);  
    }  
    public void handleMessage(Message msg) {  
         Log.e("这是新线程", ">>>>>>>新线程的测试");  
     }  
}

六、自己实现一个可以处理消息的子线程:(模仿HandlerThread)

  1. 自定义一个线程类继承Thread类;
  2. 重写run()方法,并在该方法内部实现以下三个方法
    1. Looper.prepare(); //将Looper设置到这个线程中
    2. Looper mLooper = Looper.myLooper();
    3. Looper.loop(); //开启消息循环
  3. 在另一个类中创建出该线程类对象,并启动线程;
  4. 创建一个Handler类进行线程和Looper绑定;
  5. 发送消息;
  6. 处理消息;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值