一手遮天 Android - 异步和多线程: Handler 的使用

项目地址 https://github.com/webabcd/AndroidDemo
作者 webabcd

一手遮天 Android - 异步和多线程: Handler 的使用

示例如下:

/async/HandlerDemo1.java

/**
 * Handler 的使用(Handler 用于在线程之间传递信息)
 *     本例演示后台线程向主线程发送信息
 *
 *
 * Message - 用于封装需要传递的信息(一般通过 handler 的 obtainMessage() 来构造 Message 对象,而不是 new 一个。因为 obtainMessage() 会从 Message 池中拿一个不用的过来,这样会省去创建对象的开销)
 *     what - 信息类型(以便接收方区分不同类型的信息)
 *     arg1, arg2 - 自定义整型参数
 *     obj - 具体的信息对象
 * Handler - 与相关的 MessageQueue 和 Looper 形成绑定关系,有两个作用
 *     1、将信息发送到 Handler 所属线程的 MessageQueue
 *     2、接收 Looper 获取到的信息,以便在 Handler 所属线程进行处理
 * MessageQueue - 用于保存 Message 对象的消息队列
 * Looper - 线程的 MessageQueue 管理者,循环从 MessageQueue 获取消息,并交给 Handler 处理
 *
 *
 * 通过 Handler 的 send 发送信息到 MessageQueue,以及接收 send 过来的信息
 *     sendMessage(Message msg) - 通过 send 发送 Message 对象
 *     sendMessageAtFrontOfQueue(Message msg) - 通过 send 发送 Message 对象,并将其放入 MessageQueue 队列的第一个
 *     sendMessageDelayed(Message msg, long delayMillis) - 通过 send 延迟指定的时间(相对于 SystemClock.elapsedRealtime)后发送 Message 对象
 *     sendMessageAtTime(Message msg, long uptimeMillis) - 通过 send 延迟指定的时间(相对于 SystemClock.uptimeMillis)后发送 Message 对象
 *     sendEmptyMessageDelayed(int what, long delayMillis) - 通过 send 延迟指定的时间(相对于 SystemClock.elapsedRealtime)后发送一个只有 what 值的空信息
 *     sendEmptyMessageAtTime(int what, long uptimeMillis) - 通过 send 延迟指定的时间(相对于 SystemClock.uptimeMillis)后发送一个只有 what 值的空信息
 *     通过重写 handleMessage(Message msg) 来处理 send 过来的信息
 *
 * 通过 Handler 的 post 发送信息到 MessageQueue,以及接收 post 过来的信息
 *     post(Runnable r) - 通过 post 发送消息,在指定的 Runnable(这个 Runnable 运行在 handler 所属线程)直接处理
 *     postAtFrontOfQueue(Runnable r) - 通过 post 发送消息,并将其放入 MessageQueue 队列的第一个,在指定的 Runnable(这个 Runnable 运行在 handler 所属线程)直接处理
 *     postDelayed(Runnable r, long delayMillis) - 通过 post 延迟指定的时间(相对于 SystemClock.elapsedRealtime)后发送消息,在指定的 Runnable(这个 Runnable 运行在 handler 所属线程)直接处理
 *     postAtTime(Runnable r, long uptimeMillis) - 通过 post 延迟指定的时间(相对于 SystemClock.uptimeMillis)后发送消息,在指定的 Runnable(这个 Runnable 运行在 handler 所属线程)直接处理
 *     postAtTime(Runnable r, Object token, long uptimeMillis) - token 用于信息的删除,其他和 postAtTime(Runnable r, long uptimeMillis) 一样
 *
 * 从 MessageQueue 移除指定的信息
 *     removeMessages(int what) - 移除指定 what 的 send 信息
 *     removeMessages(int what, Object object) - 移除指定 what 和 obj 的 send 信息
 *     removeCallbacks(Runnable r) - 移除 post 的指定 Runnable 的回调
 *     removeCallbacks(Runnable r, Object token) - 移除 post 的指定 Runnable 和 token 的回调
 *     removeCallbacksAndMessages(Object token) - 移除 post 的指定 token 的信息和回调
 *
 *
 * 注:
 * 1、主线程已经启动 Looper 了,不用再 Looper.prepare()/Looper.loop() 了
 * 2、新开线程需要自己写 Looper.prepare()/Looper.loop()/myLooper.quit()
 */

package com.webabcd.androiddemo.async;

import android.os.Message;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.webabcd.androiddemo.R;

public class HandlerDemo1 extends AppCompatActivity {

    private TextView _textView1;
    private TextView _textView2;
    private Button _button1;
    private Button _button2;

    private Handler _handler;

    private final int NORMAL_MESSAGE = 100;
    private final int DELAY_MESSAGE = 200;

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

        _textView1 = (TextView) findViewById(R.id.textView1);
        _textView2 = (TextView) findViewById(R.id.textView2);
        _button1 = (Button) findViewById(R.id.button1);
        _button2 = (Button) findViewById(R.id.button2);

        sample();
    }

    private void sample() {
        // 在 UI 线程实例化 Handler(默认与 Looper.myLooper() 形成绑定关系,也可以与指定的 Looper 形成绑定关系)
        _handler = new MyHandler();
        // _handler = new MyHandler(looper);

        _button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {

                // 启动一个后台线程
                Thread myThread = new MyThread();
                myThread.setName("myThread");
                myThread.setDaemon(true);
                myThread.start();

                _textView1.setText("后台线程开始执行\n");
            }
        });

        _button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                writeMessage(String.format("取消队列中的 what 值为 %d 的 send 信息的发送", DELAY_MESSAGE));
                // 取消队列中的 what 值为 200 的 send 信息的发送
                _handler.removeMessages(DELAY_MESSAGE);
            }
        });
    }

    // 自定义 Handler
    class MyHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            // 本例的 Handler 是在 UI 线程上实例化的,所以这里的 handleMessage 也是在 UI 线程上执行的
            _textView1.append(String.format("收到通过 handler 的 send 发送的信息,what:%d, arg1:%d, arg2:%d, obj:%s\n", msg.what, msg.arg1, msg.arg2, msg.obj));
        }
    }

    // 自定义 Thread
    class MyThread extends Thread {
        @Override
        public void run() {
            try {
                writeMessage("耗时任务开始执行");
                Thread.sleep(3 * 1000);
                writeMessage("耗时任务执行完毕");
            } catch (InterruptedException e) {

            }

            // 用 handler 的 obtainMessage() 来构造 Message 对象,而不是 new 一个。因为 obtainMessage() 会从 Message 池中拿一个不用的过来,这样会省去创建对象的开销
            Message msgNormal = _handler.obtainMessage();
            msgNormal.what = NORMAL_MESSAGE; // 信息类型(用于在 handleMessage 中区分不同类型的信息)
            msgNormal.arg1 = 1; // 自定义整型参数
            msgNormal.arg2 = 2; // 自定义整型参数
            msgNormal.obj = "信息 A"; // 具体的信息对象
            writeMessage(String.format("send 一个信息,what:%d, obj:%s", msgNormal.what, msgNormal.obj));
            // send 信息到 handler 所属线程
            _handler.sendMessage(msgNormal);

            Message msgDelay = _handler.obtainMessage();
            msgDelay.what = DELAY_MESSAGE;
            msgDelay.arg1 = 1;
            msgDelay.arg2 = 2;
            msgDelay.obj = "信息 B";
            writeMessage(String.format("延迟 3000 毫秒 send 一个信息,what:%d, obj:%s", msgDelay.what, msgDelay.obj));
            // 延迟 3000 毫秒后 send 信息到 handler 所属线程
            _handler.sendMessageDelayed(msgDelay, 3000);

            writeMessage("延迟 5000 毫秒 post 一个信息");
            // 延迟 5000 毫秒后 post 信息到 handler 所属线程
            _handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    // 这里是在 handler 所属线程执行的
                    _textView1.append("收到通过 handler 的 post 发送的信息\n");
                }
            }, 5000);
        }
    }

    private void writeMessage(final String message) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                _textView2.append(String.format("%s\n", message));
            }
        });
    }
}

/layout/activity_async_handlerdemo1.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/textView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="启动一个后台线程(用于向主线程发送消息)" />

    <Button
        android:id="@+id/button2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="取消队列中的 what 值为 200 的 send 信息的发送" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

项目地址 https://github.com/webabcd/AndroidDemo
作者 webabcd

posted @ 2021-06-02 09:37  webabcd  阅读(82)  评论(0编辑  收藏  举报