Handler的使用

android.os.Handler主要用于子线程发送的数据,并用此数据配合主线程更新UI。(在子线程中更新UI会报错)
由于Handler运行在主线程中,它与子线程可以通过Message对象来传递数据,我们就可以将数据放入Message中,把这些消息放入主线程队列中,之后在主线程进行更新UI。

Handler工具类在多线程中有两方面的应用

  1. 在不同的线程中发送消息。
  2. 在未来执行某个任务。
Handler类包含如下方法:

void handleMessage(Message msg): 处理消息的方法,通常被重写用于处理消息。
final boolean hasMessages(int what): 检查消息队列中是否包含what属性为指定值的消息。
final boolean hasMessages(int what, Object object): 检查消息队列中是否包含what属性为指定值得消息且object属性为制定对象的消息。

sendEmptyMessage(int what): 发送一个空的消息。
sendMessageEmptyDelayed(int what, Long delayMillis):指定多少毫秒后发送空消息
sendMessage(Message msg): 发送一个消息。
sendMessageDelayed(Message msg, Long delayMillis):指定多少毫秒后发送消息
sendMessageAtTime(Message msg, Long delayMillis): 未来某一时间发送消息。

post(Runnable): 提交计划任务马上执行。
postAtTime(Runnable, long):提交任务在未来某一时间发送消息。
postDelayed(Runnable, long): 提交任务延迟多少毫秒提交。

PS:
1. handler在使用过程中可能会发生内存泄露,其中之一的方法就是使用removeCallbacks()方法将线程对象在队列中移除。
2. sendEmptyMessage、sendMessageEmptyDelayed、sendMessage、sendMessageDelayed这四个方法的本质都是执行了sendMessageDelayed方法。将delayMillis赋值为0可以立即发送,将what转换成msg.what可以将sendMessageEmptyDelayed转换成sendMessageDelayed方法,具体可以参考Handler的源代码。

异步消息处理机制

Android中的异步消息处理主要由四个部分组成,Message、Handler、MessageQueue、和Looper。
下面对其余三个部分进行简要介绍:

1. Message

Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同的线程之间交换数据。

a. 使用arg1和arg2字段来携带一些整型数据。

b. 使用obj字段携带一个Object对象。

c. what字段是用户自定义的消息代码,这样接受这可以了解这个消息的信息。例如在子线程中令message.what = 1在handlerMessage方法中判断如果message.what ==1则text.setText(“helloworld”);

d. 其他信息可通过Bundle进行传递。

PS:Message可以通过new Message构造来创建一个新的Message,但是这种方法不建议使用,而建议使用message.obtain()来获取Message实例。因为message.obtain()是通过message池来获取实例的从而避免创建对象,从而减少内存消耗。

2. MessageQueue

MessageQueue顾名思义是消息队列的意思,它主要用于存放所有通过Handler发送的消息。这部分消息会一直存在于消息队列中,等待被处理。每个线程中只会有一个MessageQueue对象。

3. Looper

Looper是每一个线程中的MessageQueue的管家。程序创建Looper对象时,会在它的构造器中创建MessageQueue对象。调用Looper的loop()方法后就会进入到一个无限循环当中,每当发现MessageQueue中存在一条消息,就会将它取出,并传递到Handler的handleMeaage()方法中。每个线程只会有一个Looper对象。

异步消息处理流程分析:
首先在主线程当中创建一个Handler对象,并重写handlerMessage()方法。然后当子线程中需要进行UI操作时,就创建一个Message对象,并通过Handler将这条消息发送出去。之后这条消息会被添加到一个MessageQueue的队列中等待被处理,而Looper则会一直尝试从MessageQueue中取出待处理消息,最后发回到Handler的handlerMessage()方法中。由于Handler实在主线程中创建的,所以此时handlerMessage()方法中的代码也会在主线程中运行,这就可以进行UI操作了。
流程示意图如下图所示(出自郭霖《第一行代码》,侵删).

handle异步消息 handler发送异步消息_Handler

示例:

当点击按钮时滚动条每秒自增长,当滚动条满时隐藏

handle异步消息 handler发送异步消息_Android_02

public class MainActivity extends Activity implements View.OnClickListener {

    private Button changeButton;
    private ProgressBar progressBar;
    private Runnable update;
    private Handler handler;



    private void init(){
        changeButton = (Button)findViewById(R.id.change_button);
        progressBar = (ProgressBar)findViewById(R.id.progress);

        changeButton.setOnClickListener(this);

    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        init();

         handler = new Handler(){
            @Override
            public void handleMessage(Message msg){
                progressBar.setProgress(msg.arg1);
                handler.post(update);

                //如果进度条满则将线程对象在队列中移除,并且进度条取消显示
                if (msg.arg1 == 100){
                    handler.removeCallbacks(update);
                    progressBar.setVisibility(View.GONE);
                }
            }
        };

         update = new Runnable() {
            int i = 0;
            @Override
            public void run() {
                i += 10;
                Message msg = handler.obtainMessage();
                msg.arg1 = i;

                try{
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                handler.sendMessage(msg);


            }
        };
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.change_button:
                //将进度条设为可见
                progressBar.setVisibility(View.VISIBLE);
                handler.post(update);
        }
    }
}

xml文档:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/change_button"
        android:text="change"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <ProgressBar
        android:id="@+id/progress"
        android:max="100"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

参考:
《第一行代码》作者:郭霖。
详解Android Handler的使用
Android Handler Message总结
android的消息处理机制(图+源码分析)——Looper,Handler,Message
博客内容是我阅读以上资料加上自己的理解所得,有部分摘抄自以上资料,侵删。