Android中的Looper、Handler和Message工作原理

消息驱动

Android的应用程序是典型的通过消息驱动的程序,我们知道平时我们运行的Main方法,如果没有阻塞或者等待的话运行完就会退出,为了保持运行就需要阻塞或者死循环之类的方式保持程序的运行,而Android启动一个应用程序的时候同样也会启动一个主线程(UI线程),通过Looper一直循环读取MessageQueue中Message,一旦有新的Message就通过Handler来执行。

Looper

  • 启动
    进入应用程序时会调用ActivityThread1的main方法
public static final void main(String[] args) {  
        ......  
        Looper.prepareMainLooper();  
        ......  
        ActivityThread thread = new ActivityThread();  
        thread.attach(false); 
        ......  
        Looper.loop();  
        ......  
        thread.detach();  
        ......  
    } 

可以看到先调用了Looper的prepareMainLooper(),然后调用了loop()。然后我们再分别看这两个方法

  • prepareMainLooper()
public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

可以看到实际上调用了prepare方法,参数为false

  • prepare()
private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

方法中的sThreadLocal是ThreadLocal类的一个实例,用来在线程中存储变量。首先判断线程中是否已经存在了Looper,如果有的话抛出异常,可以看到这个prepare方法只能够被调用一次,如果为空的话new一个Looper实例set进sThreadLocal保存.

  • Looper构造方法
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

在new Looper实例的时候新建了一个MessageQueue实例,之前一直看到的quitAllowed 是用来标记MessageQueue实例是否可以调用它的quit() 方法的。最后看下最重要的loop方法

  • loop()
public static void loop() {
        final Looper me = myLooper();  //return sThreadLocal.get(); 就是返回之前set进sThreadLocal的Looper实例
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
            //可以看到一定要先调用Looper.prepare() 方法后才能调用loop方法
        }
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();
        //进入无限循环
        for (;;) {
            //取一条message,如果消息队列中没有消息的话会进入阻塞
            Message msg = queue.next(); // might block
            //如果取出的消息是null的话表示这个message queue已经调用了quit方法。前面看到主线程中的MessageQueue的quitAllowed为fasle,不允许退出,所以间接的主线程中的loop方法也不会return
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            ......
            //调用msg的target实例的dispatchMessage方法,其中的target就是handler,后面会讲到
            msg.target.dispatchMessage(msg);
            ......
            }
            msg.recycleUnchecked();
        }
    }

通过上面的一些方法可以看到Looper人如其名,主要就是一直循环从MessageQueue中取Message,取出Message后交给它的target(Handler)进行处理(dispatchMessage)

Handler

这个我们大家肯定非常熟悉,我们经常会遇到在非主线程中需要更新UI需求,这里就会用到Handler了,一般是在这样

private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            //处理消息,更新UI
            ......  
        }
    };

new Thread(new Runnable() {
            @Override
            public void run() {
                ......
                //耗时操作,发送消息
                handler.sendMessage(message);
            }
        }).start();
  • Handler构造方法
public Handler(Callback callback, boolean async) {
        //这个会判断一个警告,意思是说Handler class应该是一个静态类,否则可能导致内存泄漏,至于为什么可以参考链接http://stackoverflow.com/questions/11407943/this-handler-class-should-be-static-or-leaks-might-occur-incominghandler,同时也会发现上面给出的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());
            }
        }
        //获取与handler同一个线程中的Looper,因为是在主线程中创建的handler,所以这里获取到的就是上文ActivityThread中创建的Looper
        mLooper = Looper.myLooper();
        //这个可以看到如果想在我们自己的线程中使用handler,一定要先调用Looper.prepare(),主线程中系统已经为我们调用了
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        //关联Looper中的MessageQueue
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

-常用的sendMessage及其调用的方法

public final boolean sendMessage(Message msg)
    {
        //调用了下面的sendMessageDelayed方法
        return sendMessageDelayed(msg, 0);
    }

public final boolean sendEmptyMessage(int what)
    {
        //接着调用了sendEmptyMessageDelayed
        return sendEmptyMessageDelayed(what, 0);
    }

public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
    }

public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

可以看到上面一连串的调用,最终调用的还是最通用的sendMessageAtTime方法,我们自己设计方法的时候可以参考一下这种从特殊到通用的形式。接下来我们就要看下这个终极调用的enqueueMessage(queue, msg, uptimeMillis)方法

  • enqueueMessage
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        //这里就可以看到message里面的target到底是什么了,this就表示的这个handler实例自己本身
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        //这里将message加入到MessageQueue队列中去
        return queue.enqueueMessage(msg, uptimeMillis);
    }

这里我们就知道了上文中提到的msg.target.dispatchMessage(msg);中的target就是handler,最后我们就要看下dispatchMessage到底是怎么处理message的了

  • dispatchMessage
public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            //按照上文的用法,最终调用了这个方法
            handleMessage(msg);
        }
    }

按照上文handler的用法我们没有定义msg.callback,new的handler也没用传mCallback,所以最终执行了handleMessage(msg);这个方法。

  • handleMessage
/**
     * Subclasses must implement this to receive messages.
     */
    public void handleMessage(Message msg) {
    }

可以看到这是个空方法,是不是想起了什么,这不就是我们new Handler的时候覆盖的方法吗,所以最终收到Message后的执行代码到了主线程里面我们覆盖的handleMessage方法中了,所以我们就可以愉快的做更新UI之类的操作了。handler还有一个我们常用的方法post,再看下post到底是怎么回事。

  • post(Runnable r)
//有时候我们可能会这样使用
handler.post(new Runnable() {
            @Override
            public void run() {
                txtHandler.setText("456");
            }
        });

//下面是post的源码,看注释可以知道post的参数Runnable只是为了加入到消息队列中被执行的,执行的线程仍然是handler所在的线程,并没有创建新的线程,所以当我们的handler在主线程中创建时我们还是可以愉快的在Runnable的run方法中更新UI
/**
     * Causes the Runnable r to be added to the message queue.
     * The runnable will be run on the thread to which this handler is 
     * attached. 
     *  
     * @param r The Runnable that will be executed.
     */
public final boolean post(Runnable r)
    {
       //这里又是一连串的从特殊到通用方法的调用,下面一次贴出来
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

//这里是上面post中被调用的方法
private static Message getPostMessage(Runnable r) {
        //不需要直接new,而是直接用Message.obtain(),我们查看obtain方法可以看到内部维护的message池,可以让我们更好的复用message,所以比较推荐这种用法
        Message m = Message.obtain();
        //然后把我们传进来的Runnable赋给了message的callback,并把这个message实例返回
        m.callback = r;
        return m;
    }

//这里是上面post中被调用的方法
public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        //发现这个post的方法和sendMessage方法最终都调用了这个方法,就是把message加入到了message queue中去了,不同的是这次的msg.callback不为null了
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
  • 再看dispatchMessage
public void dispatchMessage(Message msg) {
        //这次通过handler的post方法这个条件就成立了
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

//上面的handleCallback(msg);调用的方法
private static void handleCallback(Message message) {
        //从上文代码知道callback其实就是我们通过post方法传进来的Runnable对象,这里调用它的run方法。
        message.callback.run();
    }

总结

上文总共涉及到了Looper,Handler,Message,MessageQueue四个对象,主要讲的是他们在UI线程中是如何工作的:当android应用程序启动时会调用Looper的prepare和loop方法,这样就有了一个无限循环,循环的就是MessageQueue里面放的Message,我们可以在主线程中定义Handler,通过Handler来发送Message以及通过定义Handler时覆盖的handleMessage方法或者调用post方法时传入的Runnable的run方法来处理Looper在MessageQueue中取得的Message。当然在我们自己的线程中也是可以用Looper,Handler,只不过需要我们自己调用Looper的方法,android也为我们提供了HandlerThread来方便我们开发。语言描述能力有限,最后用一张图来总结:
enter image description here
参考:
Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
Android应用程序消息处理机制(Looper、Handler)分析
Android中Thread、Handler、Looper、MessageQueue的原理分析

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值