Android中使用Handler&Looper更新UI范例

5年前在学校错过一次Android,等到现在才开始补救。但愿还不晚。
本文以一个更新UI的例子来讲述Looper和Handler如何配合使用。

本文所写范例仅供研究、学习之用,不喜勿喷,敬请谅解!


UI目标:
1. 用户滑动seekBar至任意值(例如X%),然后点击UPDATE按钮,等待2s后progressBar更新到seekBar的相同值X%,底部editText_log中显示出“set progress=X”的日志。
Android中使用Handler&Looper更新UI范例_第1张图片

多线程设计

据说,不可以做任何阻塞UI的工作!

本文设计一共两个线程:UI线程 + Looper线程。

两个线程的职责分别是:
UI线程:UI启动、处理UI消息、更新UI。
Looper线程:处理耗时2s的复杂任务,处理完毕后返回消息给UI线程。

本文设计了两个Handler,分别是:MainHandler + LooperHandler。

两个Handler的职责分别是:
MainHandler:
1. 由Looper线程调用,发送更新UI的消息到UI线程;
2. 由UI线程处理Message时被调用处理UI更新的Message,更新UI。
LooperHandler:
1. 由UI线程调用,发送处理任务的消息给Looper线程;
2. 在Looper线程中调用,处理从UI线程发来的耗时任务。

两个线程的时序图如下所示:
Android中使用Handler&Looper更新UI范例_第2张图片
Android中使用Handler&Looper更新UI范例_第3张图片

部分实现代码如下:

package com.frank.simplehandler_0611;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.SeekBar;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "SimpleHandler_0611";

    public static class MyLooperHandler extends Handler {
        private MainHandler mMainHandler = null;
        private static final int MSG_SET_PROGRESS = 0;

        public MyLooperHandler(Looper looper, MainHandler mainHandler) {
            super(looper);
            mMainHandler = mainHandler;
        }

        /****
         * handleMessage called in LooperThread.
         *
         * @param msg message object.
         */
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == MSG_SET_PROGRESS) {
                Log.d(TAG, "MyLooperHandler.handleMessage msg.what=" + msg.what + " arg1=" + msg.arg1);
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                mMainHandler.updateProgress(msg.arg1);
            }
        }

        /***
         * setProgress called in Main Thread.
         *
         * @param arg0 new seek bar value.
         */
        public void setProgress(int arg0) {
            Log.d(TAG, "MyLooperHandler.setProgress arg0=" + arg0);
            Message msg = Message.obtain();
            msg.what = MSG_SET_PROGRESS;
            msg.arg1 = arg0;
            sendMessage(msg);
        }
    }

    public class MainHandler extends Handler {
        public static final int MSG_SET_PROGRESS_MAIN = 1;

        public MainHandler(Looper looper) {
            super(looper);
        }

        /***
         * handleMessage called in UI thread
         *
         * @param msg
         */
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == MSG_SET_PROGRESS_MAIN) {
                int prg = msg.arg1;
                String content = (String) msg.obj;
                Log.d(TAG, "MainHandler.handleMessage msg.what=" + msg.what + " progress=" + prg + " content=" + content);
                if (progressBar_01 != null) {
                    progressBar_01.setProgress(prg);
                }
                if (editText_log != null) {
                    editText_log.append(content);
                }
            }
        }

        /***
         * updateProgress called in MyLooperThread
         * This message is send to Main Thread for  UI update
         *
         * @param arg
         */
        public void updateProgress(int arg) {
            Log.d(TAG, "MainHandler.updateProgress arg=" + arg);
            Message msg = Message.obtain();
            msg.what = MSG_SET_PROGRESS_MAIN;
            msg.arg1 = arg;
            msg.obj = String.format("set progress=%d", arg);
            sendMessage(msg);
        }
    }


    MyLooperHandler myLooperHandler = null;
    MainHandler mainHandler = null;

    EditText editText_log = null;
    SeekBar seekBar_01 = null;
    ProgressBar progressBar_01 = null;

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

        Log.d(TAG, "MainActivity.onCreate UI thread running...");
        // UI components initialize
        editText_log = (EditText) findViewById(R.id.editText_log);
        seekBar_01 = (SeekBar) findViewById(R.id.seekBar_01);
        progressBar_01 = (ProgressBar) findViewById(R.id.progressBar_01);
        findViewById(R.id.button_action).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (seekBar_01 != null) {
                    int prg = seekBar_01.getProgress();
                    if (myLooperHandler != null) {
                        Log.d(TAG, "MainActivity.onCreate.button_action.onClick prg=" + prg);
                        myLooperHandler.setProgress(prg);
                    }
                }
            }
        });

        MyLooperThread myLooperThread = new MyLooperThread("Worker");
        myLooperThread.start();
        mainHandler = new MainHandler(getMainLooper());
        myLooperHandler = new MyLooperHandler(myLooperThread.getLooper(), mainHandler);
    }
}

代码工程详见:
https://github.com/wangqunfeng/AndroidDemos/tree/master/apps/SimpleHandler_0611

你可能感兴趣的:(Android)