zoukankan      html  css  js  c++  java
  • 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()方法.





     




    qq3061280@163.com
  • 相关阅读:
    C# 中的委托和事件
    css样式大全(整理版)
    (转)VS2010 快捷键
    委托小例子
    .NET中Cache的使用
    ObjectiveC面向对象编程继承
    ObjectiveC简介
    ObjectiveC面向对象编程实例化对象、构造函数
    MSSql的多表关联的update语句
    ObjectC 与 Java 区别
  • 原文地址:https://www.cnblogs.com/aibuli/p/4db568e7d49e4d0b2c74b54546a4498c.html
Copyright © 2011-2022 走看看