非主线程更新UI:Handler

练习心得

整个实现涉及Looper、Handler、MessageQueue、Message 4个类

  • Looper:一个线程只能有一个Looper实例,通过Looper.prepare()获取实例,构造实例过程同时生成MessageQueue
  • Handler:负责发送消息和处理消息(即负责收发)
  • MessageQueue:一个线程仅能有一个,以队列先进先出的方式存储Handler发送的消息
  • Looper.loop()方法以死循环的方式不断从MessageQueue拿取Message交给Handler处理,一定要放到最后一条语句,因为是死循环获取队列中的消息,会阻塞同一线程的其它语句执行。可以通过调用Looper.quit()终止死循环
  • Message:消息载体,注意每次handler投递的message都要是一个新的实例,否则报IllegalStateException,This message is already in use

代码样例

/**
 * Created by Rambo
 */

public class MyActivity extends MainActivity {

    private EditText myEditText = null;
    private Button stop = null;
    private HashMap asynTaskParams = new HashMap<>();
    private Handler mainThreadHandler = null;
    private Handler otherThreadHandler = null;
    private final int UPDATE_EDITTEXT = 0x01;
    private final int UPDATE_BUTTONTEXT = 0x02;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        myEditText = (EditText) findViewById(R.id.myEditText);
        stop = (Button) findViewById(R.id.stop);

        // 主线程定义handler用于处理其它线程发送过来的消息
        mainThreadHandler = new Handler() {
            /**
             * 消息处理回调
             * @param msg 消息信息
             */
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {// 通过msg.what区分消息来源
                    case UPDATE_EDITTEXT:
                        Log.v(TAG, "otherThread call MainThread handler running:" + Thread.currentThread().getName());
                        myEditText.setText(msg.getData().get("threadIndex").toString());
                        break;
                    case UPDATE_BUTTONTEXT:
                        Log.v(TAG, "timer call MainThread handler running:" + Thread.currentThread().getName());
                        stop.setText("stop" + msg.getData().get("timerIndex").toString());
                        break;
                }
            }
        };

        // 定义新线程,执行耗时任务
        Thread otherThread = new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare(); // 创建非主线程的Looper,同时在Looper的构造方法中创建MessageQueue(先进先出队列),一个线程中只能有一个Looper和MessageQueue
                // 非主线程处理器,其它线程可通过handler与该线程进行数据通讯,这也是线程间通讯的一种机制
                otherThreadHandler = new Handler(){
                    @Override
                    public void handleMessage(Message msg) {
                        super.handleMessage(msg);
                        switch (msg.what){
                            default:
                                Log.v(TAG, "otherThread-otherThreadHandler.handleMessage");
                        }
                    }
                };


                Log.v(TAG, "otherThread running:" + Thread.currentThread().getName());
                try {
                    for (int index = 0; index < 5; index++) {
                        // 定义要发给主线程handler的消息,每次handler投递的message都要是一个新的实例,否则报IllegalStateException,This message is already in use
                        Message otherThreadMsg = new Message();
                        otherThreadMsg.what = UPDATE_EDITTEXT;
                        Bundle data = new Bundle();
                        data.putInt("threadIndex", index);
                        Thread.sleep(1000);
                        otherThreadMsg.setData(data);
                        // 通过主线程handler实例发送消息,相当于自发自收
                        mainThreadHandler.sendMessage(otherThreadMsg);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                // 该语句触发Looper不断从MessageQueue中获取新消息交由handler处理,
                // 一定要放到最后一条语句,因为是死循环获取队列中的消息,会阻塞同一线程的其它语句执行
                Looper.loop();
            }

        });
        otherThread.start();

        // 定时任务,会起新的线程执行run代码块
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                Log.v(TAG, "TimerThread running:" + Thread.currentThread().getName());
                try {
                    for (int index = 0; index < 5; index++) {
                        // 注意每次handler投递的message都要是一个新的实例,否则报IllegalStateException,This message is already in use
                        Message timerThreadMsg = new Message();
                        timerThreadMsg.what = UPDATE_BUTTONTEXT;
                        Bundle data = new Bundle();
                        data.putInt("timerIndex", index);
                        Thread.sleep(1000);
                        timerThreadMsg.setData(data);
                        mainThreadHandler.sendMessage(timerThreadMsg);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }, 0);// 表示不延迟

        while (otherThreadHandler == null){

        }
        otherThreadHandler.sendEmptyMessage(0);
    }

运行日志如下:

非主线程更新UI:Handler_第1张图片
日志

你可能感兴趣的:(非主线程更新UI:Handler)