面试篇源码篇

系统Handler源码分析

2017-05-04  本文已影响9人  MrWang915

参考 http://www.jianshu.com/p/ac50ba6ba3a2

          http://www.jianshu.com/p/aa6b6152217d

几个要点

消息其中包括:

     我们自己的操作消息(客户端的 Handler)

      系统的操作消息(系统 Handler):比如启动 Activity 等四大组件(例如       突然来电话的时候跳转到电话界面)

线程不安全问题归根结底主要涉及到变量的多线程访问问题,例如变量的临界问题、值错误、并发问题等

1 系统的handler类名为大写的H (继承Handler)

2 为ActivityThread 的成员变量,在 new ActivityThread 的时候,系统的 Handler 就初始

3 在 main 方法里面,然后创建了 Looper,然后开启消息循环。之所以我们的APP能够一直运行着,就是因为 Looper.loop() 里面是一个死循环:

public static void loop() {

   for(;;) {    }

}

4 在非主线程里面我们也可以搞一个 Handler,但是需要我们主动去为当前的子线程绑定一个 Looper,并且启动消息循环。

5 post方法(封装了带Runnable的Message) 最终都是调用sendMessageAtTime方法,把消息放到消息队列里面:

6 消息并不是一直在队列的尾部添加的,而是可以指定时间,如果是立马需要执行的消息,就会插到队列的头部,就会立马处理,如此类推。

7 ThreadLocal 是JDK提供的一个解决线程不安全的类,线程不安全问题归根结底主要涉及到变量的多线程访问问题,例如变量的临界问题、值错误、并发问题等。这里利用ThreadLocal 绑定了 Looper 以及线程,就可以避免其他线程去访问当前线程的 Looper 了。

8  Looper 与线程的关联是通过 ThreadLocal 来进行的

9  MessageQueue 是Looper对象的成员变量 (消息队列是通过链表实现 指向下一个结点)

Looper与当前线程绑定

调用prepare(prepareMainLooper())方法来关联线程和Looper  //sThreadLocal.set(newLooper(quitAllowed));

Looper的成员变量sThreadLocal

static final ThreadLocal sThreadLocal =newThreadLocal();

在prepare方法中new了一个Looper并且设置到sThreadLocal里面sThreadLocal.set(newLooper(quitAllowed));

消息池的概念

1 Message Pool消息池的概念——重复利用Message (利用享元模式去循环利用)

2 通过obtain方法取出一条消息的时候,如果发现当前的消息池不为空,那就直接重复利用Message(已经被创建过和handle过的);如果为空就重新 new 一个消息。这就是一种享元设计模式的概念

3 消息的去取出并不是直接就从队列的头部取出的,而是根据了消息的when时间参数有关的,因为我们可以发送延时消息、也可以发送一个指定时间点的消息

迭代消息过程

1 首先拿到Looper对象(me),如果当前的线程没有Looper,那么就会抛出异常,这就是为什么在子线程里面创建Handler如果不手动创建和启动Looper会报错的原因。

2 Looper的成员变量MessageQueue,在MessageQueue里面不断地去取消息

for(;;) { 

      Message msg = queue.next();// might block

if(msg ==null) {

// No message indicates that the message queue is quitting.

return;

        }

//处理消息

try{ 

 msg.target.dispatchMessage(msg); 

  }

finally{ }  

   } 

msg.recycleUnchecked();//回收消息}

Handler、Looper是怎么关联

在初始化Handler类中

public Handler(Callback callback, booleanasync){   

 mLooper = Looper.myLooper();//见下文备注 第二块核心代码

//如果当前线程(子线程)没有Looper,就需要我们程序要去手动prepare以及启动loop方法了

//子线程里面默认没有Looper循环器

if(mLooper ==null) {

thrownewRuntimeException("Can't create handler inside thread that has not called Looper.prepare()"); 

   }  

  mQueue = mLooper.mQueue; 

   mCallback = callback;  

  mAsynchronous =async;

}

第二块核心代码

public static @Nullable Looper myLooper(){

returns  ThreadLocal.get();//返回与当前线程绑定的Looper

}

上一篇 下一篇

猜你喜欢

热点阅读