您的位置:首页 > 其它

Handler机制.源码分析

2016-10-02 22:30 232 查看
Handler机制的原理 :Android提供了handler 和 looper 来满足线程之间的通信
Handler是先进先出的原则
一个线程可以产生一个looper对象,由它去管理线程里面消息队列 MessageQueue
Handler 你可以构造handler对象来与looper沟通.可以发送消息 和处理消息

 MessageQueue 用来存放线程放入的消息

 线程 一般值的是主线程 UIthread
Android启动程序的时候会替他建立一个MessageQueue

 

.Handler创建消息

消息池
 消息池
 
 
 
Handler发送消息
ThreadLocal
Handler 处理消息
 andriod提供了Handler 和 Looper 来满足线程间的通信。Handler先进先出原则。Looper类用来管理特定线程内对象之间的消息交换(MessageExchange)。

1)Looper: 一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列)。

2)Handler: 你可以构造Handler对象来与Looper沟通,以便push新消息到MessageQueue里;或者接收Looper从Message
Queue取出)所送来的消息。

3) Message Queue(消息队列):用来存放线程放入的消息。
4)线程:UIthread 通常就是main thread,而Android启动程序时会替它建立一个MessageQueue。
1.Handler创建消息

        每一个消息都需要被指定的Handler处理,通过Handler创建消息便可以完成此功能。Android消息机制中引入了消息池。Handler创建 消息时首先查询消息池中是否有消息存在,如果有直接从消息池中取得,如果没有则重新初始化一个消息实例。使用消息池的好处是:消息不被使用时,并不作为垃
圾回收,而是放入消息池,可供下次Handler创建消息时使用。消息池提高了消息对象的复用,减少系统垃圾回收的次数。消息的创建流程如图所示。



2.Handler发送消息
UI主线程初始化第一个Handler时会通过ThreadLocal创建一个Looper,该Looper与UI主线程一一对应。使用
ThreadLocal的目的是保证每一个线程只创建唯一一个Looper。之后其他Handler初始化的时候直接获取第一个Handler创建的 Looper。Looper初始化的时候会创建一个消息队列MessageQueue。至此,主线程、消息循环、消息队列之间的关系是1:1:1。
Handler、Looper、MessageQueue的初始化流程如图所示:



Hander持有对UI主线程消息队列MessageQueue和消息循环Looper的引用,子线程可以通过Handler将消息发送到UI线程的消息队列MessageQueue中。
3.Handler处理消息
UI主线程通过Looper循环查询消息队列UI_MQ,当发现有消息存在时会将消息从消息队列中取出。首先分析消息,通过消息的参数判断该消息对应的Handler,然后将消息分发到指定的Handler进行处理。
子线程通过Handler、Looper与UI主线程通信的流程如图所示。



 
 相关的术语 :
通信的同步 Synchronous指向客户端发送请求后,必须要在服务端有回应后客户端才继续发送其它的请求,所以这时所有请求将会在服务端得到同步,直到服务端返回请求。
通信的异步 Asynchronous  指客户端在发送请求后,不必等待服务端的回应就可以发送下一个请求。

 
 所谓同步调用,就是在一个函数或方法调用时,没有得到结果之前,该调用就不返回,直到返回 结果。异步调用和同步是相对的,在一个异步调用发起后,被调用者立即返回给调用者,但是调用者不能立刻得到结果,被调用都在实际处理这个调用的请求完成 后,通过状态、通知或回调等方式来通知调用者请求处理的结果。

 
 
 Android的消息处理有三个核心的类
Looper handler 和 message 其实还有一个MessageQueue 但是它被封装在looper中,不会直接和它打交道,所以不算是核心的类.

消息类Message类  主要的功能是进行消息的封装,同时可以指定消息的操作形式
Int whatobject obj      Handler getTraget
尽管message有默认的构造,但是我们应该是通过Message.ontain() 来从消息池中获取消息对象,节省资源
如果是只是简单地携带int信息,优先使用Message.arg1和Message.arg2来传递信息,这比Bundle更省内存

 善用message.what
来标示信息,以便不同的方式来处理message

 消息通道 looper 系统会自动创建looper对象,但是如果是用户自定义的一个类中,就需要手动的调用looper中的方法.才可以启动looper对象
表面的意思是循环者,它被设计一个普通的线程变成looper线程,所说的looper线程就是循环工作的线程
.looper.prepare()  ;    处理其他,比如实例化handler
……  looper.loop()

 一个线程只可以有一个looper对象,为什么???

 
 
public
 
class Looper 
{

    
// 每个线程中的Looper对象其实是一个ThreadLocal,即线程本地存储(TLS)对象

    
private
 
static
 
final
 ThreadLocal sThreadLocal = 
new
 ThreadLocal();

    
// Looper内的消息队列

    
final
 MessageQueue mQueue;

    
// 当前线程

    Thread mThread;

    
//其他属性

    
// 每个Looper对象中有它的消息队列,和它所属的线程

    
private Looper() 
{

        mQueue = 
new
 MessageQueue();

        mRun = 
true
;

        mThread = Thread.currentThread();

    }

    
// 我们调用该方法会在调用线程的TLS中创建Looper对象

    
public static final void prepare() 
{

        
if
 (sThreadLocal.get() != 
null
) {

            
// 试图在有Looper的线程中再次创建Looper将抛出异常

            
throw
 
new
 RuntimeException(
"Only one Looper may be created per thread"
);

        }

        sThreadLocal.set(
new
 Looper());

    }

    
// 其他方法

}
[/code]
  看源码 ,可以看出创建looper对象其实就是将looper对象定义为ThreadLocal,如果这个对象以前定义了,妮又尝试着去重新的定义,就是说threaLocal.get()!=null
这个时候对象存在,就会爆异常 .

  

 looper.loop() 这个代表着启动looper 线程开始工作了.它不断的从队列里面取出消息.每次去的是第一个消息.源码分析 :
调用这个方法后,内部的执行流程
 1.获取当前线程的looper对象
Looper me = myLooper();这个方法内部其实就是返回 ThreadLocal.get()

 2. 获取消息队列
MessageQueue queue = me.mQueue;

 3. 开启一个while死循环
用队列的对象取出下一个消息
Message msg = queue.
next
();
判断消息是否为空,如果是空,就不会继续执行了
如果不是空,将消息交给handler
msg.target.dispatchMessage(msg);
msg.recycle();回收msg资源
 

 looper中的其他的方法 myLooper()   getThread()
       quit()  结束looper的循环 public void quit() 
{

        
// 创建一个空的message,它的target为NULL,表示结束循环消息

        Message msg = Message.obtain();

        
// 发出消息

        mQueue.enqueueMessage(msg, 
0
);

    }
[/code]
 综上,Looper有以下几个要点:
1)每个线程有且只能有一个Looper对象,它是一个ThreadLocal
2)Looper内部有一个消息队列,loop()方法调用后线程开始不断从队列中取出消息执行
3)Looper使一个线程变成Looper线程。
那么,我们如何操作Message Queue上的消息呢?这就是Handler的用处了

 
 
 
 消息操作类  handler
处理消息,但是很小气,只处理自己发出的消息

 默认关联当前线程的looper  

mLooper = Looper.myLooper();判断looper是不是空的,如果是空的就爆异常,就是指handler只可以在looper线程中使用,关联looper的消息队列,因为他的消息要发送到looper的消息队列中public class LooperThread extends Thread {    private Handler handler1;    private Handler handler2;     @Override    public void run() {        // 将当前线程初始化为Looper线程        Looper.prepare();                // 实例化两个handler        handler1 = new Handler();        handler2 = new Handler();                // 开始循环处理消息队列        Looper.loop();    }}一个线程可以有多个handler 但是只能有一个looper有了handler之后 就可以发送消息;了 post(Runnable) postAtTime(Runnable, long) postDelayed(Runnable, long) sendEmptyMessage(int)sendMessage(Message)sendMessageAtTime(Message, long)sendMessageDelayed(Message, long) post发送消息最后都是把里面的Runnable封装成了message // 此方法用于向关联的MQ上发送Runnable对象,它的run方法将在handler关联的looper线程中执行    public final boolean post(Runnable r)    {       // 注意getPostMessage(r)将runnable封装成message       return  sendMessageDelayed(getPostMessage(r), 0);    }     private final Message getPostMessage(Runnable r) {        Message m = Message.obtain();  //得到空的message        m.callback = r;  //将runnable设为message的callback,        return m;    }     public boolean sendMessageAtTime(Message msg, long uptimeMillis)    {        boolean sent = false;        MessageQueue queue = mQueue;        if (queue != null) {            msg.target = this;  // message的target必须设为该handler!            sent = queue.enqueueMessage(msg, uptimeMillis);        }        else {            RuntimeException e = new RuntimeException(                this + " sendMessageAtTime() called with no mQueue");            Log.w("Looper", e.getMessage(), e);        }        return sent;    } 发送消息的时候 ,设置target为当前发送消息的handler,这样就可以方便的找到处理消息的handler对象

发送消息之后,是怎么处理消息的 dispathMessage(Message msg) 和 钩子方法 handleMessage(Message msg)dispatchMessage(Message msg) {         (msg.callback != ) {                        handleCallback(msg);        }  {                         (mCallback != ) {                                  (mCallback.handleMessage(msg)) {                    ;                }            }                        handleMessage(msg);        }    }               handleCallback(Message message) {        message.callback.run();      }          handleMessage(Message msg) {    } 

来自为知笔记(Wiz)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: