Handler进行线程通信以及对其源码解析

一、子线程向子线程通信

package com.study.yang.handlercodedemo

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.Log
import android.view.View
import kotlinx.android.synthetic.main.activity_child_to_child.*

/**
 * 子线程向子线程发送消息
 */
class ChildToChildActivity : AppCompatActivity() {

    var handler: Handler? = null
    var content: String = ""

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_child_to_child)

        object : Thread() {
            override fun run() {
                super.run()
                Looper.prepare()
                handler = object : Handler() {
                    override fun handleMessage(msg: Message?) {
                        super.handleMessage(msg)
                        msg?.apply {
                            if (obj is String) {
                                Log.e("thread::", "111message::$this")
                                content = obj as String
                                runOnUiThread {
                                    tv_thread1.text = content
                                }
                            }
                        }
                    }
                }
                Looper.loop()
            }
        }.start()

    }

    fun sendMsg(view: View) {
        object : Thread() {
            override fun run() {
                super.run()
                handler?.apply {
                    val message = obtainMessage()
                    message?.obj = "子线程2"
                    sendMessage(message)
                }
            }
        }.start()
    }
}

二、子线程向主线程通信

package com.study.yang.handlercodedemo

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.os.Message
import kotlinx.android.synthetic.main.activity_child_to_main.*

/**
 * 子线程向主线程发送消息
 */
class ChildToMainActivity : AppCompatActivity() {

    /**
     * 此处创建的Handler,默认就是在主线程中。
     * ActivityThread中的main方法
     * public static void main(String[] args) {
     *   ...
     *   Looper.prepareMainLooper();
     *  ...
     *  Looper.loop();
     *  }
     */
    var handler = object : Handler() {
        override fun handleMessage(msg: Message?) {
            super.handleMessage(msg)
            msg?.apply {
                val text = obj as String
                tv.text = text
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_child_to_main)
        object : Thread() {
            override fun run() {
                super.run()
                val message = Message.obtain()
                message.obj = "品兰"
                handler.sendMessage(message)
            }
        }.start()
    }
}

三、主线程向子线程通信

package com.study.yang.handlercodedemo

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.Log
import android.view.View

/**
 * 主线程向子线程发送消息
 */
class MainToChildActivity : AppCompatActivity() {

    var handler: Handler? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main_to_child)

        object : Thread() {
            override fun run() {
                super.run()
                Looper.prepare()
                handler = object : Handler() {
                    override fun handleMessage(msg: Message?) {
                        super.handleMessage(msg)
                        msg?.apply {
                            if (obj is String) {
                                Log.e("thread::", "111message::$this")
                            }
                        }
                    }
                }
                Looper.loop()
            }
        }.start()

    }

    fun sendMsg(view: View){
        handler?.apply {
            val message = obtainMessage()
            message.obj="我在主线程向子线程发送消息"
            sendMessage(message)
        }
    }
}

四、Handler源码解析

4.1 为什在主线程中创建Handler的时候不用调用Looper.prepare()和Looper.loop()
此处创建的Handler,默认就是在主线程中。
ActivityThread中的main方法
public static void main(String[] args) {
...
Looper.prepareMainLooper();
...
Looper.loop();
}
4.2 子线程中创建Handler注意事项
子线程中创建Handler,这段示例代码可以在Looper源码中找到
class LooperThread extends Thread {
	public Handler mHandler;
       public void run() {
            Looper.prepare();
 
           mHandler = new Handler() {
               public void handleMessage(Message msg) {
                   // process incoming messages here
               }
            };
  
            Looper.loop();
        }
  }
4.3 Handler是如何做到线程隔离的
Looper中的static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();说明虚拟机中只会存在ThreadLocal唯一对象

每个线程的Thread成为Handler线程时,都需要Looper.perpar()方法,都会创建新的Looper。

每个线程都有新的Looper,每个线程都有新得ThreadLocalMap,每个ThreadLocalMap的key值都是虚拟机中ThreadLocal唯一对象,对应值为当前Looper对象。

Message->Handler->Activity,假设存在延迟消息,那么将会导致持有的Activity的引用与Message的生命周期不一致,从而导致内存泄漏。

Message.obtain方法产生Message,享元模式减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式

主线程与子线程如何实现通信
Handler、MessageQuene以及Looper若在主线程,子线程使用Handler对象发送消息到消息队列时,Looper轮询时将会在主线程中取出消息并处理消息,实现通信。

利用ThreadLocal实现线程隔离,ThreadLocal内部维护了一个ThreadLocalMap对象。它的存储数据结构是
以Key-Value的形式进行的,其中Key就是当前ThreadLocal的对象,Value是Looper对象。
4.4 Handler源码
创建Handler的过程中走的流程如下,调用Looper类中的Looper.prepare()方法
 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");
     }
    //将创建的Looper保存到ThreadLocal中
    sThreadLocal.set(new Looper(quitAllowed));
 }

 //Looper类中创建Looper的同时创建该Handler的消息队列
 private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
 }

 调用Handler类中的构造方法创建Handler,具体如下:
   public Handler(Callback callback, boolean async) {
       ...
       //从ThreadLocal中取出之前保存的Looper
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        //该Looper中的消息队列
        mQueue = mLooper.mQueue;
      ....
    }


 //调用Handler类中的sendMessage方法发送消息,最终调用
  enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)进行消息队列的排序。

 //调用MessageQueue类的enqueueMessage方法进行消息排列
  按照消息执行时间进行排序,此处用的是优先队列算法
   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 {
            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;
    }
    
最后调用Looper.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.");
        }
        //找到相应的消息队列
        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;
            }
            ....
        }
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值