android异步消息处理机制

如果尝试在程序里创建两个Handler对象,一个在主线程中创建,一个在子线程创建.
public class MainActivity extends ActionBarActivity {
    private Handler mh1;
    private Handler mh2;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mh1=new Handler();
        new Thread(new Runnable() {
            @Override
            public void run() {
                mh2=new Handler();
            }
        }).start();
    }
} 
运行程序会发现,在子线程中创建的Handler的对象会导致程序崩溃,报错如下:
说的是不能再没有Looper.prepare()的线程中创建Handler对象.

如果在子线程中调用了Looper.prepare().
public class MainActivity extends ActionBarActivity {
    private Handler mh1;
    private Handler mh2;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mh1=new Handler();
        new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare();
                mh2=new Handler();
            }
        }).start();
    }  
再运行.就不会出现这个问题了.
看看Handler的无参构造函数.


public Handler() {  
    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 = null;  
}  
可以看到   ,mLooper是Looper的对象,如果mLooper为空,就会抛出一个运行异常.提示的错误正是刚才运行的错误.
再看一下,什么时候Looper对象才为空
public static final Looper myLooper() {  
    return (Looper)sThreadLocal.get();  
方法很简单,就是从sThreadLocal取出Looper,如果sThreadLocal存在Looper则返回looper对象,否则返回空.
结合上面运行,第一遍因为没有Looper.prepare()方法而报Looper对象为空,  第二遍因为有了Looper.prepare()而不会出现这种情况.
所以sThreadLocal里面的Looper对象肯定是Looper.prepare()方法传进去的.
Looper.prepare()方法源码:
public static final void prepare() {  
    if (sThreadLocal.get() != null) {  
        throw new RuntimeException("Only one Looper may be created per thread");  
    }  
    sThreadLocal.set(new Looper());  
在这里,可以看到sThreadLocal首先判断是否有Looper对象,如果已经有了,则抛出异常,否则创建一个Looper对象set进去.
看出,每个线程中最多只能有一个Looper对象.

看看刚才的代码,发现只有子线程中调用了Looper.prepare()方法,主线程并没有调用.
这是因为在程序启动时,系统已经自动调用了Looper.prepare()方法.
查看ActivityThread中的main()方法

public static void main(String[] args) {  
    SamplingProfilerIntegration.start();  
    CloseGuard.setEnabled(false);  
    Environment.initForCurrentUser();  
    EventLogger.setReporter(new EventLoggingReporter());  
    Process.setArgV0("<pre-initialized>");  
    Looper.prepareMainLooper();  
    ActivityThread thread = new ActivityThread();  
    thread.attach(false);  
    if (sMainThreadHandler == null) {  
        sMainThreadHandler = thread.getHandler();  
    }  
    AsyncTask.init();  
    if (false) {  
        Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));  
    }  
    Looper.loop();  
    throw new RuntimeException("Main thread loop unexpectedly exited");  
}  
可以看到这里有一个Looper.prepareMainLooper()方法.再看到这个方法内部

public static final void prepareMainLooper() {  
    prepare();  
    setMainLooper(myLooper());  
    if (Process.supportsProcesses()) {  
        myLooper().mQueue.mQuitAllowed = false;  
    }  
}  
到这里,已经明白:主线程中始终会存在一个Looper对象,而在子线程中需要调用Looper.prepare()去创建.



再看Handler是如何发送消息
public class MainActivity extends ActionBarActivity {
    private Handler mh1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mh1=new Handler();
        new Thread(new Runnable() {
            @Override
            public void run() {
                Message meg=Message.obtain();
                meg.obj="data";
                mh1.sendMessage(meg);
            }
        }).start();
    }
} 
在线程中,用Handler对象发送一个Message.
可是,Handler到底是把Message发送到哪里?为什么又会在Handler的handleMessage()方法中可以获取这条Message.
其实Handler提供了多个发送消息的方法,除了sendMessageAtFrontOfQueue()外,所有方法都到经过sendMessageAtTime()方法.
sendMessageAtTime()源码如下:
public boolean sendMessageAtTime(Message msg, long uptimeMillis)  
{  
    boolean sent = false;  
    MessageQueue queue = mQueue;  
    if (queue != null) {  
        msg.target = this;  
        sent = queue.enqueueMessage(msg, uptimeMillis);  
    }  
    else {  
        RuntimeException e = new RuntimeException(  
            this + " sendMessageAtTime() called with no mQueue");  
        Log.w("Looper", e.getMessage(), e);  
    }  
    return sent;  
}  
方法接受两个参数,第一个就是Message对象,第二个则是需要延迟发送的毫秒数.如果不是调用的sendMessageDelayed(),延迟数都为0.
MessageQueue,是一个消息队列.提供了出队与入队的方法.
而这里面的enqueueMessage就是入队方法.

final boolean enqueueMessage(Message msg, long when) {  
    if (msg.when != 0) {  
        throw new AndroidRuntimeException(msg + " This message is already in use.");  
    }  
    if (msg.target == null && !mQuitAllowed) {  
        throw new RuntimeException("Main thread not allowed to quit");  
    }  
    synchronized (this) {  
        if (mQuiting) {  
            RuntimeException e = new RuntimeException(msg.target + " sending message to a Handler on a dead thread");  
            Log.w("MessageQueue", e.getMessage(), e);  
            return false;  
        } else if (msg.target == null) {  
            mQuiting = true;  
        }  
        msg.when = when;  
        Message p = mMessages;  
        if (p == null || when == 0 || when < p.when) {  
            msg.next = p;  
            mMessages = msg;  
            this.notify();  
        } else {  
            Message prev = null;  
            while (p != null && p.when <= when) {  
                prev = p;  
                p = p.next;  
            }  
            msg.next = prev.next;  
            prev.next = msg;  
            this.notify();  
        }  
    }  
    return true;  
}  

MessageQueue并没有使用一个集合将所有的消息保存起来,它只使用了mMessages对象表示未处理的消息.
其实入队的方法就是将所有的消息按uptimeMillis时间排序,具体操作方法根据时间顺序调用msg.next.
而从每一个消息指定它的下一个消息是什么.
而出队的方法,就在Looper.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) {  
                return;  
            }  
            if (me.mLogging!= null) me.mLogging.println(  
                    ">>>>> Dispatching to " + msg.target + " "  
                    + msg.callback + ": " + msg.what  
                    );  
            msg.target.dispatchMessage(msg);  
            if (me.mLogging!= null) me.mLogging.println(  
                    "<<<<< Finished to    " + msg.target + " "  
                    + msg.callback);  
            msg.recycle();  
        }  
    }  
从代码的  while(true)  开始就是一个死循环,然后不停的调用MessageQueue的next方法,next()就是消息队列出队的方法.
它的简单逻辑就是如果当前MessageQueue中存在mMessages(待处理消息) ,就将这个消息出队,然后让下一个消息成为mMessages,否则就形成一个堵塞状态,一直等到有新消息入队.

每当一个消息出队,就将它传递到msg.target的dispatchMessage()方法中.
而msg.target就是Handler对象.

public void dispatchMessage(Message msg) {  
    if (msg.callback != null) {  
        handleCallback(msg);  
    } else {  
        if (mCallback != null) {  
            if (mCallback.handleMessage(msg)) {  
                return;  
            }  
        }  
        handleMessage(msg);  
    }  
}
如果mCallback不为空,则调用mCallBack的handleMessage()方法,否则调用Handler的handleMessage()方法.


除了发送消息,还有几种方法可以在子线程中更新UI
1.Handler的post()方法

2.View的post()方法

3.Activity的runOnUiThread()方法.





 




posted @ 2014-09-11 23:23  冷冷汤圆  阅读(250)  评论(0编辑  收藏  举报