您的位置:首页 > 产品设计 > UI/UE

Android 消息处理Handler、 Message 、MessageQueue、Looper、Thread协调配合

2013-09-27 11:08 597 查看
android界面控制在ui线程里面,任何子线程都不允许直接操作ui而是借助handler或者activity的post方法等。handler又是如何处理线程间通信的?

1、Handler的声明放在ui主线程中声明然后传递给子线程:

Handler handler=new Handler()
{
public void handleMessage(android.os.Message msg) {

};
};


Handler的源码:

public Handler() {
this(null, false);
}

    public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

我们主要看黑色部分,函数调用 Looper.mylooper(),返回得到一个looper实例。该实例有个mQueue的成员变量属于MessageQueue的类型。

mCallback为null,mAsynchrous 为false 。

callback可以指定message的处理回调,而不是使用handler的默认handMessage()处理消息的回调。

mAsynchrous 表示该handle是否可以处理异步消息目前还不清楚如何区别别的消息类型。

先看下Looper

public class Looper {
private static final String TAG = "Looper";

// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper;  // guarded by Looper.class

final MessageQueue mQueue;
final Thread mThread;
volatile boolean mRun;

private Printer mLogging;


创建handler的时候便可以通过Looper.mylooper得到当前线程的looper 通过looper可以得到当前线程的消息队列 mMessageQueue 。Handler调用sendMessage的时候将message压入mMessageQueue。到此为止消息已经成功加入到消息队列当中,那么消息是什么时候,怎么样处理地呢?

回头看看Looper这个类,在创建 Handler的时候 Looper.mylooper()这个Looper的静态方法又是如何得到looper的呢。查找looper的成员函数,可以找到我们熟悉的Looper.prepare()以及Looper.prepareMain()由此可断定,当系统启动的时候即当ui主线程创建的时候android 内部便调用了Looper.prepareMainLooper()方法

/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself.  See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}

再调用完此方法后便调用Looper.looper()方法,详情参考android源码。可以看到looper方法里面有个循环不断的从mMessageQueue里面拿出消息,再交由message的target的dispatchMessage处理。message的target是一个handler对象,在加入mMessageQueue的时候添加:

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

disPatchMessage方法如下:

/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}


Message 自己有callback是一个runable ,handler也有个Callback 是一个handler类的内部接口,当希望使用自己接口来处理消息回调,可以实现该内部接口的handleMessage(Message msg) 方法。当处理消息的时候优先使用message的callback 其次使用传入handler的callback,再就是handler的handmessage的方法。

这样一波三折子线程的message通过handler传入到主线程的消息队列中并且在主线中执行。这样便可以在子线程中操作ui线程的东西。


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