Android消息机制 1 – 实战

一. 概述

在Android中,进程间通信主流的有Binder,Socket,而线程之间的通信则有Android消息机制,在分析源码之前,先复习一下如何使用。

二. 传统使用

[-> SecondActivity.java]

package com.dopezhi.handlerdemo;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

public class SecondActivity extends AppCompatActivity {

    private final String TAG = "SecondActivity";

    public final int MSG_GET = 1;
    public final int MSG_RESULT = 2;

    public Handler mUiHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(@NonNull Message msg) {
            Log.i(TAG, "mUiHandler handleMessage thread : " + Thread.currentThread());
            switch (msg.what) {
                case MSG_RESULT:
                    Toast.makeText(getApplicationContext(), (String) msg.obj, Toast.LENGTH_LONG).show();
                    break;
                default:
                    break;
            }
        }
    };

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

        LooperThread looperThread = new LooperThread("looper_thread");
        looperThread.start();

        findViewById(R.id.get_second).setOnClickListener(v -> {
            looperThread.mSubHandler.sendEmptyMessage(MSG_GET);
        });

    }

    class LooperThread extends Thread {
        public Handler mSubHandler;

        public LooperThread(String name) {
            super(name);
        }

        @Override
        public void run() {
            Looper.prepare();
            mSubHandler = new Handler(Looper.myLooper()) {
                @Override
                public void handleMessage(@NonNull Message msg) {
                    Log.i(TAG, "mSubHandler handler handleMessage thread : " + Thread.currentThread());
                    switch (msg.what) {
                        case MSG_GET:
                            double number = Math.random();
                            Message message = new Message();
                            message.what = MSG_RESULT;
                            message.obj = "dopezhi : " + number;
                            mUiHandler.sendMessage(message);
                            break;
                        default:
                            break;
                    }
                }
            };
            Looper.loop();
        }
    }
}

复制代码

在主线程中创建另外一个线程(looper_thread),并在looper_thread中初始化Looper,创建子线程的mSubHandler,并与子线程的Looper挂钩。

主线程中初始化mUIhandler,与主线程Looper挂钩。

点击按钮,主线程向子线程发送消息MSG_GET,子线程收到消息后,向主线程发送MSG_RESULT消息,最终主线程通过Toast展示子线程发过来的消息的内容。

三. 封装好的轮子-HandlerThread

为什么会有HandlerThread?
1.要让子线程能处理消息,首先要创建内部类继承Thread,之后调Looper.prepare,Looper.Loop,比较麻烦
2.如果主线程想拿到子线程的Looper,虽然子线程执行了Looper.prepare去创建Looper,但是并不一定马上调度到并创建好,容易造成Null Point。

[-> MainActivity.java]

package com.dopezhi.handlerdemo;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private final static String TAG = "MainActivity";

    protected final int MSG_GET = 1;
    protected final int MSG_RESULT = 2;

    private HandlerThread mHandlerThread;

    //子线程中的Handler实例
    private Handler mSubTreadHandler;

    private Handler mUiHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(@NonNull Message msg) {
            Log.i(TAG, "mUiHandler handleMessage thread : " + Thread.currentThread());
            switch (msg.what) {
                case MSG_RESULT:
                    Toast.makeText(getApplicationContext(), (String) msg.obj, Toast.LENGTH_LONG).show();
                    break;
                default:
                    throw new IllegalStateException("Unexpected value: " + msg.what);
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.i(TAG, "onCreate thread : " + Thread.currentThread());
        //点击该按钮,向子线程handler发消息
        findViewById(R.id.get).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mSubTreadHandler.sendEmptyMessage(MSG_GET);
                Log.i(TAG,"I frist");
            }
        });

        findViewById(R.id.jumoToSecond).setOnClickListener(v -> {
            Intent intent = new Intent();
            intent.setClass(this, SecondActivity.class);
            startActivity(intent);
        });
        initHandlerThread();

    }

    private void initHandlerThread() {
        //创建HandlerThread实例
        mHandlerThread = new HandlerThread("handler_thread");
        //开始运行线程
        mHandlerThread.start();
        //获取HandlerThread线程中的Looper实例
        Looper loop = mHandlerThread.getLooper();

        //NEW,当消息队列没有消息时,会回调到该idelHandler执行方法
        Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
            @Override
            public boolean queueIdle() {
                Log.i(TAG,"The queue is empty");
                return false;
            }
        });
        //创建Handler与线程绑定
        mSubTreadHandler = new Handler(loop) {
            @Override
            public void handleMessage(@NonNull Message msg) {
                Log.i(TAG, "mSubThreadHandler handleMessage thread : " + Thread.currentThread());
                switch (msg.what) {
                    case MSG_GET:
                        try {
                            Thread.sleep(5000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        Log.i(TAG,"sorry , I first");
                        double number = Math.random();
                        String result = "dopezhi: " + number;
                        //向UI线程发送消息,更新UI
                        Message message = new Message();
                        message.what = MSG_RESULT;
                        message.obj = result;
                        //子线程收到消息后,向主线程Handler发送消息
                        mUiHandler.sendMessage(message);
                        break;
                    default:
                        break;
                }

            }
        };

    }
}
复制代码

可以看到,开启一个子线程并执行消息循环并不需要后面那么多步骤,只需要new HandlerThread.start就可以了。

[-> HandlerThread.java]

public class HandlerThread extends Thread

    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }
复制代码

可以看一下HandlerThread的源码,HandlerThread本质上也是Thread,重写了run方法,执行start时会初始化Looper,并开启Looper循环。如果在这之前调用mHanderThread.getLooper(),会wait(),直到Looper创建好调用notifyAll。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享