Android笔记(三十) Android中线程之间的通信(二)Handler消息传递机制

什么是Handler

         之前说过了,Android不允许主线程(MainThread)外的线程(WorkerThread)去修改UI组件,但是又不能把所有的更新UI的操作都放在主线程中去(会造成ANR),那么只能单独启动一个子线程(WorkerThread)去处理,处理完成之后,将结果通知给UI主线程,子线程和主线程的通信就用到了Handler。

Handler、Looper和MessageQueue的基本原理

         先看一下他们的职责:

         Handler——处理者,负责发送以及处理Message。

         MessageQueue——消息队列,用来存放Handler发送过来的消息,采用FIFO(first in first out)规则将Message以链表的方式串联起来的,等待Looper的抽取。

         Looper——消息泵,不断的从消息队列中取出消息并回传给Handler

         1. Handler对象调用obtainMessage()方法获取Message对象

         2. 调用sendMessage(Message msg)方法将消息发送到消息队列(MessageQueue)中

         3. Looper循环这从消息队列中取出msg

         4. 调用Handler对象的handleMessage(Message msg)方法,将取出的msg传给Handler

         Handler将消息传到队列,Looper从队列中拿到消息,然后又传给了Handler,这似乎是一个无用功,我们通过代码来看一下。

package cn.lixyz.handlertest;

import android.app.Activity;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

/**
 * 实现点击按钮,开始播放幻灯片,每张幻灯片间隔2s。
 */

public class MainActivity extends Activity {
    
    private Button button;
    private Handler handler;   

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

        button = (Button) findViewById(R.id.button);       

        handler = new MyHandler();

        button.setOnClickListener(new ButtonOnClickListener());

    }
    
    class ButtonOnClickListener implements View.OnClickListener {

        @Override
        public void onClick(View v) {
            Thread t = new ChangePicThread();
            t.start();
        }
    }
    
    class ChangePicThread extends Thread {
        @Override
        public void run() {
            super.run();
            try {
                Thread.sleep(1 * 1000);
                Log.d("TTTTT", "---->" + Thread.currentThread().getName());
                Message msg = handler.obtainMessage();
                msg.what = 100;
                handler.sendMessage(msg);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    //创建内部类,继承Handler,用来创建Handle对象
    class MyHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Log.d("TTTTT", "====>" + Thread.currentThread().getName());
            int i = msg.what;
            Log.d("TTTTT", "message=" + i);
        }
    }
}
MainActivity.java
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="30dp"
        android:text="sendMessage" />

</LinearLayout>
activity_main.xml

         点击按钮,查看log

09-16 10:55:12.064  12614-12669/cn.lixyz.handlertest D/TTTTT﹕ ---->Thread-213
09-16 10:55:12.064  12614-12614/cn.lixyz.handlertest D/TTTTT﹕ ====>main
09-16 10:55:12.064  12614-12614/cn.lixyz.handlertest D/TTTTT﹕ message=100

         可以看到,ChangePicThread的线程名是Thread-213,MyHandler的线程名是main,那message也传递过来了,那我们不就可以在线程中将所需要处理的内容处理好,将结果传给Handler,由Handler去修改UI么

一个简单的Handler例子

         点击按钮,开始播放幻灯片。

package cn.lixyz.handlertest;

import android.app.Activity;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

/**
 * 实现点击按钮,开始播放幻灯片,每张幻灯片间隔2s。
 */

public class MainActivity extends Activity {

    private ImageView imageView;
    private Button button;
    private Handler handler;
    private int[] images = {R.drawable.pic1,
            R.drawable.pic2, R.drawable.pic3, R.drawable.pic4, R.drawable.pic5, R.drawable.pic6,};
    private int index = 0;

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

        button = (Button) findViewById(R.id.button);
        imageView = (ImageView) findViewById(R.id.imageView);

        handler = new MyHandler();

        button.setOnClickListener(new ButtonOnClickListener());

    }

    //创建内部类,实现OnClickListener接口,用于注册监听按钮开始事件
    class ButtonOnClickListener implements View.OnClickListener {

        @Override
        public void onClick(View v) {
            Thread t = new ChangePicThread();
            t.start();
        }
    }

    //创建内部类,用户执行2s变换幻灯片
    class ChangePicThread extends Thread {
        @Override
        public void run() {
            super.run();
            try {

                while (true) {
                    Object obj = new Object();
                    synchronized (obj) {
                        Message msg = handler.obtainMessage();
                        msg.obj = index;
                        handler.sendMessage(msg);
                        index++;
                        Thread.sleep(2 * 1000);
                        if (index >= images.length ) {
                            index = 0;
                        }
                    }
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    //
    class MyHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            int i = (int) msg.obj;
            BitmapDrawable bd = (BitmapDrawable) imageView.getDrawable();
            if (bd != null && !bd.getBitmap().isRecycled()) {
                bd.getBitmap().recycle();
            }
            imageView.setImageResource(images[i]);
        }
    }
}
MainActivity.java
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="30dp"
        android:text="点击播放" />

</LinearLayout>
activity_main.xml
原文地址:https://www.cnblogs.com/xs104/p/4814858.html