xichao1980

导航

Handler

在Handler 异步实现时,涉及到 Handler, Looper, Message,Thread四个对象

Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。

Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。

MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。

Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper

Thread:线程,负责调度整个消息循环,即消息循环的执行场所。

 

实现异步的流程:

主线程启动子线程 -> 子线程运行并生成Message然后发送到MessageQueue -> Looper获取Message并传递给Handler ->Handler逐个获取Looper中的Message并进行UI更新等操作。

线程在空闲(原子操作之间的间隙)时启动Looper的loop(),里面是for(;;),直到没有message才会结束。

所以HandleMessage不能有太耗时操作,message过多也会对UI刷新有影响。

 

Framework在Activity,Service等系统组件的主线程(UI线程---这个名称不好,比如Service就没UI)中会默认建Looper。

一个线程对应一个Looper,一个Looper对应一个MessageQueue。

每个线程最多只有一个Looper对象,它的本质是一个ThreadLocal,而ThreadLocal是在JDK1.2中引入的,它为解决多线程程序的并发问题提供了一种新思路。

子线程创建Handler要传入new Looper,如果自己定义子线程的Looper,方法如下:

    public static prepare();
    public static myLooper();
    public static loop();
    public void quit();
使用方法如下:
1. 在每个线程的run()方法中的最开始调用Looper.prepare(),这是为线程初始化消息队列。
2. 之后调用Looper.myLooper()获取此Looper对象的引用。这不是必须的,但是如果你需要保存Looper对象的话,一定要在prepare()之后,否则调用在此对象上的方法不一定有效果,如looper.quit()就不会退出。
3. 在run()方法中添加Handler来处理消息
4. 添加Looper.loop()调用,这是让线程的消息队列开始运行,可以接收消息了。
5. 在想要退出消息循环时,调用Looper.quit()注意,这个方法是要在对象上面调用,很明显,用对象的意思就是要退出具体哪个Looper。如果run()中无其他操作,线程也将终止运行。

 

另外一种常用方法,简便:

mHandler = new Handler();
        mRunnable = new Runnable() {

            @Override
            public void run() {
                mTextView.setText("haha");
            }
        };
        mButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                new Thread() {
                    public void run() {
                        mHandler.post(mRunnable);
                    }
                }.start();
            }
        });
    }

使用Handler的post()方法就显得UI的更新处理非常简单:在一个Runnable对象中更新UI,然后在另一个线程中通过Handler的post()执行该更新动作。值得注意的是,我们就算不用新开一个新线程照样可以更新UI,因为UI的更新线程就是Handler的创建线程---主线程。

表面上Handler似乎可以发送两种消息:Runnable对象和Message对象,实际上Runnable对象会被封装成Message对象。

 

总结:

·      Handler的处理过程运行在创建Handler的线程里

·      一个Looper对应一个MessageQueue

·      一个线程对应一个Looper

·      一个Looper可以对应多个Handler

·      不确定当前线程时,更新UI时尽量调用post方法

posted on 2014-03-19 13:43  xichao1980  阅读(276)  评论(0编辑  收藏  举报