您的位置:首页 > 移动开发 > Android开发

[置顶] Android消息机制小探索

2016-03-18 21:12 423 查看
           Android消息机制主要指handler的运行机制(线程之间的切换),线程在默认的情况下是没有支持消息循环的,即Thread类的run方法执行完内容便推出循环,当然主线程那是后文啦!因此,Handler的运行需要底层的MessageQueue和Looper的支持。MessageQueue主要采用单链表实现(便于插入和删除),MessageQueue只是一个消息存储的单元不能去处理消息,Looper填补了这个空白(无线循环的去查寻消息),Handler在创建的时候需要采用当前线程的Looper来构建内部消息系统,先来看一段典型例子

class LooperThread extends Thread {
public Handler mHandler;

public void run() {
Looper.prepare();

mHandler = new Handler() {
public void handleMessage(Message msg) {
// process messages here
}
};

Looper.loop();
}
}        那问题来了:正如前文提到的,Handler是在创建的时候调用当前线程的Looper对象构建消息内部消息系统,那Handler内部是如何获取当前线程的Looper对象呢?这就要使用到ThreadLocal(这是何方神圣),ThreadLocal可以在不同的线程中互不干扰的存储以及提供数据,因此Handler通过TheadLocal在不同线程中很容易获取当前线程的Looper对象。
        当然,这么说可能我们还是不会明白ThreadLocal到底是怎么做到呢?在Thread中有一个专门的成员用于存储线程的ThreadLocal数据(values),在values内部有一个table数组,当不同线程访问同一个get方法时候,ThreadLocal内部会从各自线程中取出这个数组,然后再根据当前线程的ThreadLocal索引获取values值。这样说是不是好多了。

       解决上面小疑问那马上来看看如何在飞主线程中创建消息循环系统。  直接调用Looper类的prepare方法创,实质上,在主线中也是调用prepare方法创建的~!~。

**
* Initialize the current thread as a looper. This gives you a chance to
* create handlers that then reference this looper, before actually starting
* the loop. Be sure to call {@link #loop()} after calling this method, and
* end it by calling {@link #quit()}.
*/
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException(
"Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}       这段代码上面已经做了详尽的解析,注意最后一行:prepare方法调用Looper类的私有构造方法创建Looper对象,在构造方法中创建消息队列,然后将当前线程对象保存起来。还是前面提到的消息队列只不过是一个单链表~~简单的数据结构,单链表效率正是在于插入以及删除操作,这些也是MessageQueue的操作enqueueMessage(插入)和next(取出并从消息队列中删除这条消息)
private Looper() {
// 私有构造方法,在prepare()方法里面调用
// 创建消息队列
mQueue = new MessageQueue();
mRun = true;
// 当前线程
mThread = Thread.currentThread();
}       谈到Looper类,不得不说loop方法,调用这个方法消息才真正进入循环。Looer.loop()方法是个死循环,在循环中不断的调用Queue的next方法读取消息,如果过没有消息next方法处以阻塞状态;唯一可以结束当前循环的方法是next返回null(looper的quit方法会被调用),当队列中有消息时,Looper的loop方法便会调用Handler中的diapatchMessage方法处理消息。
/**
* Run the message queue in this thread. Be sure to call {@link #quit()} to
* end the loop.
*/
public static final void loop() {
// 进入当前线程的消息循环
Looper me = myLooper();
MessageQueue queue = me.mQueue;
while (true) {

// 从队列中取出消息
Message msg = queue.next(); // might block

if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
// other codes...

// 分发消息
msg.target.dispatchMessage(msg);
// 消息的target是Handler类型的对象

// other codes...

// 释放清理
msg.recycleUnchecked();
}
}
}       Handler的post和send方法本质上是调用sendMessage方法,sendMessage方法的工作就是将消息入队。looper当一个消息道来,在loop方法中调用Handler的dispatchMessage方法处理消息
 /**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {

// 首先,处理Message自己的callback,调用其run方法
if (msg.callback != null) {
handleCallback(msg);
}
else {
// 其次,调用Handler自留的接口对象
// 这个成员变量声明时的注释如下:
/**
* Callback interface you can use when instantiating a Handler to
* avoid having to implement your own subclass of Handler.
*/
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}

// 最后,调用handleMessage方法处理消息,Handler类中这个方法为空,子类可以重写这个方法
handleMessage(msg);
}
}       dispatchMessage方法有调用了handleMessage方法,handleMessage方法实际上是一个空方法,我们重写该方法就可以实现消息处理。
       谈完了非主线程消息循环系统,最后来小探下UI线程又是什么情况呢?Android程序的运行入口点可以认为是android.app.ActivityThread类的main()方法。

public static final void main(String[] args) {
// other codes...

// 创建主线程循环
Looper.prepareMainLooper();
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
}

ActivityThread thread = new ActivityThread();
thread.attach(false);

// other codes...

// 进入当前线程(此时是主线程)消息循环
Looper.loop();

// other codes...

thread.detach();
// other codes...

     这个main方法创建了主线程循环,通过prepareMainLooper()创建主线程的Looper以及MessageQueue,并通过loop方法开启主线程消息循环。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: