介绍

      在平时的安卓开发过程中,Handler一定不少见,Handler是Android消息机制的上层接口,这使得在开发过程中只需要和Handler交互即可。很多人认为Handler的作用就是更新UI,的确没错,但是更新UI仅仅是Handler的一个特殊的使用场景。具体来说,就是有时候需要在子线程做一些耗时操作,比如说访问网络或者耗时的I/O操作,当这些耗时操作完成时,程序的UI进行相应的改变。由于安卓开发规范的限制,我们不能在子线程中访问UI控件,因为UI的控件是线程非安全的,这个时候通过Handler就可以将更新UI的操作切换到主线程中执行。下面我就通过代码来演示Handler的基本用法。

基本用法
我这里先上代码,以下是最基本的用法
public class MainActivity extends AppCompatActivity {

    private TextView textView;
    private String TAG = "MainActivity";
    private int i = 0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView) findViewById(R.id.textView);
    }
    public void onClick(View v){
        ++i;
        //创建新的线程
        new Thread(){
            @Override
            public void run() {
                super.run();
                doSendMsg();
            }
        }.start();
    }

    /**
     * 在子线程中做耗时操作,完成之后,通知Handler更新UI
     */
    private void doSendMsg(){
        try {
            Thread.sleep(1000);//模拟耗时操作
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Message message = Message.obtain();
        message.arg1 = i;
        message.what = 1;
        mHandler.sendMessage(message);
    }

    Handler mHandler = new Handler(){
        /**
         * handleMessage接收消息后进行相应的处理
         * @param msg
         */
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if(msg.what==1){
                textView.setText(msg.arg1+"");
            }
        }
    };
}
以下是运行效果:

Android handler不起作用_Android handler不起作用

以上代码是Handler里的最基本的操作了,相信读者非常容易看懂。不过我还是解释一下,首先按钮响应了点击事件之后,创建了一个新的线程,模拟耗时操作让线程休眠了1秒钟,操作完成之后将需要传递的数据装入Message对象,再通过mHandler.sendMessage()方法将消息发送出去,此时实现了Handler的handleMessage()方法就能够接收到此消息,这时候已经是在UI线程了,所以能够在方法里面进行相应的UI更新。以上是最典型的Handler更新UI操作,至于Handler的其他用法,可以参考官方文档,里面有非常详细全面的解释.

https://developer.android.com/reference/android/os/Handler.html

原理解析

那么Handler是怎么工作的呢?这时候需要认识这三个类,分别是: Message(消息), MessageQueue(消息队列), Looper(消息循环者)。

  • Message :android.os.Message是定义一个Messge包含必要的描述和属性数据,并且此对象可以被发送给android.os.Handler处理。属性字段:arg1、arg2、what、obj、replyTo等;其中arg1和arg2是用来存放整型数据的;what是用来保存消息标示的;obj是Object类型的任意对象;replyTo是消息管理器,会关联到一个handler,handler就是处理其中的消息。通常对Message对象不是直接new出来的,只要调用handler中的obtainMessage方法来直接获得Message对象。
  • MessageQueue :MessageQueue的中文翻译是消息队列,顾名思义,它的内部存储了一组消息,以队列的形式对外提供插入和删除的工作。虽然叫消息队列,但是它的内部存储结构并不是真正的队列,而是采用单链表的数据结构来存储消息。它只是用来存储消息,而并不能处理消息,Looper就填补了这个功能。
  • Looper:在MessageQueue里存储了消息之后,Looper就会以无限循环的形式去查是否有新消息,如果有的话就去处理消息,否则就是一直等待着。Looper中还有一个特殊的概念就是ThreadLocal,ThreadLocal并不是线程,它是用来在每个线程中存储数据。Handler创建的时候就会采用ThreadLocal获取当前线程的Looper构造消息循环系统。还有一点非常要注意的是,工作线程是默认是没有Looper的,若要在线程中使用就需要创建Looper,否则就会抛出Can’t create handler inside thread that has not called Looper.prepare(),意思是不能创建Handler因为Looper没有执行Looper.prepare()方法,尚未初始化。而UI线程即主线程中,是默认初始化了Looper的,所以不需要再UI线程再次执行Looper.prepare()方法了。那么在工作线程中如何初始化Looper的代码如下:
new Thread("Thread#2"){
    @Override
    public void run(){
        Looper.prepared();
        Handler handler = new Handler();
        Looper.loop();
    };
}.start();
工作流程

Handler的主要工作包含消息的发送与接收过程。消息的发送通过post和send的一系列方法来实现,其实post的一系列方法最终还是通过send来实现的。当Handler发送了消息之后,MessageQueue里就插入了一条消息,然后MessageQueue就会返回这条消息给Looper,Looper接收到消息之后就开始处理了,最终消息由Looper交给Handler处理,即Handler的dispatchMessage方法会被调用,这时Handler就进入了处理消息的阶段,最后经过一系列的判断之后,就会调用handleMessage()方法了。

Android handler不起作用_Android handler不起作用_02

以上就是Handler机制的基本原理,相信通过上面介绍之后,读者对Handler能够有更清楚的认识。