Android开发Android知识安卓资源收集

Android Handler总结

2016-08-21  本文已影响737人  sunbinqiang

Handler是什么

Handler是Android提供的用来更新UI的一套机制, 也是一套消息处理机制,我们可以通过它来发送和处理消息。
Handler在Android Framework中应用也非常广泛: 其中,Activity生命周期回调的方法被调用的过程就是通过Handler来实现的。

为什么要使用Handler

Android设计的时候就封装了一套消息创建,传递,处理机制,如果不遵循这样的机制更新UI界面,会抛出异常错误(非UI线程更新UI)。
另外,关于UI线程和更新UI,官网有如下一段话的解释:

When a process is created for your application, its main thread is dedicated to running a message queue that takes care of managing the top-level application objects (activities, broadcast receivers, etc) and any windows they create. You can create your own threads, and communicate back with the main application thread through a Handler.

当应用启动的时候, 会创建一个进程,进程的主线程运行着消息队列,管理着最高级别的应用对象(例如activity,broadcast receivers 以及其他界面上的内容),这个主线程就是我们常说的UI线程。当我们创建自己的线程的时候,我们想要和主线程进行通信,就必须通过Handler来实现。

Handler 基本用法

官网的解释:

There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.

翻译不太通顺,直接用代码来解释一下吧:
1, Handler提供了以下方法:
post(Runnable) [postAtTime(Runnable, long)](https://developer.android.com/reference/android/os/Handler.html#postAtTime(java.lang.Runnable, long)) [postDelayed(Runnable, long)](https://developer.android.com/reference/android/os/Handler.html#postDelayed(java.lang.Runnable, long)) sendEmptyMessage(int) sendMessage(Message) [sendMessageAtTime(Message, long)](https://developer.android.com/reference/android/os/Handler.html#sendMessageAtTime(android.os.Message, long)) [sendMessageDelayed(Message, long)](https://developer.android.com/reference/android/os/Handler.html#sendMessageDelayed(android.os.Message, long))
其中post Runnable 是将Runnable发送给其他线程(创建handler的线程)执行;
send message一类的方法则是发送消息, 与下面的handleMessage相对应:
2, 重写Handler的handleMessage方法,可以通过message类型判断执行条件,而handleMessage的执行是在其他线程中,可以做UI更新的操作。

Handler handler = new Handler(){    
    @Override    
    public void handleMessage(Message msg) {  
            super.handleMessage(msg);
            ...//更新UI
    }
};

实例

下面是一个通过Handler实现TextView控件读秒操作的例子, 在App的首页广告闪屏中很常见,直接上代码:

mHandler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        //计时
        int msgId = msg.what;
        if(msgId == MSG_ID_COUNT){
            int count = getCount();
                ignoreBtn.setText("跳过 " + count);
            if(count > 0){
                mHandler.sendEmptyMessageDelayed(MSG_ID_COUNT, 1000);
            }
        }else if(msg.what == MSG_ID_IGNORE){
            launchApp();
        }else if(msg.what == MSG_ID_NOAD){
            launchApp();
        }
    }
};

private int getCount(){
    mCount--;
    if(mCount <= 0){
        launchApp();
    }
    return mCount;
}

写了一个Handler,通过重写handleMessage处理3个消息。我们会在程序刚启动的时候,发送一个MSG_ID_COUNT消息,开始首页广告的倒计时:

mHandler.sendEmptyMessageDelayed(MSG_ID_COUNT, 1000);

其中第二个参数表示延时的事件1000ms
当用户点击“跳过”按钮的时候,我们会发送一个MSG_ID_IGNORE消息:

mHandler.sendEmptyMessageDelayed(MSG_ID_IGNORE, 100);

这样,就实现了一个基本的广告跳过的功能。可以看到,Handler实现了2个基本功能:

1, 可以指定消息发送的时间,倒计时功能;
2, 可以在handleMessage方法中更新UI,倒计时界面;

Handler原理

说到Handler的原理,我们先来看看Handler的源码,以下是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();   // 获取Looper  
    if (mLooper == null) {  
        throw new RuntimeException(  
            "Can't create handler inside thread that has not called Looper.prepare()");  
    }  
    mQueue = mLooper.mQueue;       // 获取消息队列  
    mCallback = null;  
}

上述注释的两行代码,可以看到有两个概念: **Looper, MessageQueue **
首先说说这两个概念:

  1. Looper, 包含一个消息队列MessageQueue, 作为消息封装的载体。
    主要方法: Looper.looper() , 一个死循环方法, 不断地查看MessageQueue中是否有新的消息;
  2. MessageQueue, 一个消息队列, 可以添加消息,处理消息;

那么,在Handler的构造方法中,获取了Looper和MessageQueue并保存为全局变量,是为了与Handler进行关联。
下面是一张简明的图,很好的阐述了Handler, Looper, MessageQueue三者之间的关系:


关系,来自stackoverflow

总结: Handler负责发送消息, Looper负责接收Handler发送的消息,并直接把消息传回Handler自己,后续就会调用回调等方法(handleMessage)来处理。

为什么要设计Handler更新UI
上面的关系图,我们可以看到,如果想更新UI, 通过Handler的sendMessage方法发送消息, 然后作为UI Thread的Looper会轮询消息队列MessageQueue, 从而保证了多线程下UI更新的正确性。也就是说,如果没有Handler机制,在多线程下更新UI,我们必须使用锁来保护避免并发的问题。


update 来自《Android开发艺术》
Android中的UI并不是线程安全的, 如果在多线程下访问UI,则会导致UI界面状态不可控制的情况; 而如果加上锁的机制,有两个缺点:1, 将UI访问的逻辑变的非常复杂; 2, 会导致访问UI的效率变低。
所以,基于这两个缺点,在多线程中操作UI,就提供了Handler机制。

参考资料:
慕课网 Handler详解
Handler官网
stackoverflow What is the relationship between Looper, Handler and MessageQueue in Android?

上一篇下一篇

猜你喜欢

热点阅读