一 前言
有 Android 开发经验的同学都清楚, UI 的更新必须在主线程中进行, 且主线程不能被阻塞, 否则系统 ANR 异常. 我们往往做一些数据处理是耗时操作, 必须要在子线程中进行, 然后再将处理后的数据切换到主线程去更新 UI, 这便是线程切换.
线程切换的本质是 "数据的切换", 即将数据从一个线程传递到另一个线程.
二 案例描述
老风格, 先给出场景案例, 然后通过线程切换实现该案例.
案例: 在线程 A 中调用 API 发送一段数据 data,data 最终通过线程切换由线程 B 执行数据处理动作.
三 线程切换基本原理
所谓线程切换, 本质就是 "数据在线程间切换", 即将一个线程 A 中的数据, 传递到另一个线程 B 执行数据处理操作. 基于以上认知, 比较自然的实现逻就是: 将线程 A 中的数据进行拷贝, 线程 B 获取到拷贝数据, 然后进行处理, 如下图所示.
四 案例实现代码
首先创建一个 DataHandler 类, 该类中定义了数据拷贝方法和数据处理线程. 在 DataHandler 中定义了一个用于数据副本存放的成员变量 mData; 外部模块可通过 sendData()将数据拷贝到 DataHandler 中; 在 DataHandler 构造中初始化数据处理线程 (线程 B); 该线程重写的 run() 方法中用一个 while 循环不停查询数据副本 mData 的值, 当检测到 mData 有数据时, 则执行数据处理动作, 数据处理完成后, 将数副本 mData 清空. 这样便实现了将其他外部线程中的数据切换到线程 B 中处理.
- public class DataHandler {
- // 数据副本
- private String mData;
- public DataHandler() {
- initSwithThread();
- }
- /**
- * 发送数据, 供外部调用
- * @param data
- */
- public void sendData(String data) {
- // 拷贝数据
- mData = data;
- }
- private void initSwithThread() {
- new Thread(new Runnable() {
- @Override
- public void run() {
- while(true) {
- if(null != mData && mData.length()> 0) {
- System.out.println("process data, run in thread :"
- + Thread.currentThread().getName() + ", data =" + mData);
- // 数据发送后, 清除数据副本 mData
- mData = null;
- }
- // 为了能够清晰看清结果这里让 thread 休眠 1s
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }, "ThreadB").start();
- }
- }
测试类 ThreadTest 中创建线程 A, 然后在 A 中调用 DataHandler 实例的数据拷贝方法 sendData()将数据切换到线程 B 中处理.
- public class ThreadTest {
- public static DataHandler mHandler;
- public static void main(String[] args) {
- mHandler = new DataHandler();
- Thread threadA = new Thread(new Runnable() {
- @Override
- public void run() {
- // 线程 A 中发送数据
- String data = "hello code 9527";
- System.out.println("send data, run in thread :"
- + Thread.currentThread().getName() + ", data =" + data);
- // 通过 DataHandler 将数据拷贝到线程 B 中处理
- mHandler.sendData(data);
- }
- }, "threadA");
- threadA.start();
- }
- }
运行结果:
- send data, run in thread : threadA, data = hello code 9527
- process data, run in thread : ThreadB, data = hello code 9527
从结果可以看出数据 "hello code 9527" 在线程 A 中被 DataHandler 拷贝出来, 副本存放到 DataHandler 中, 然后通过线程 B 中进行处理. 这样就实现了数据在线程间的切换. 实现切换的 "灵魂操作" 便是 "数据拷贝" 和 "目标线程对拷贝副本的轮询". 实现原理是不是很简单? 其实 Android 的 Handler 机制也是基于这种原理实现的, 有兴趣的同学可以深入分析一下 Handler 源码.
来源: https://www.cnblogs.com/woyuwozhouxuanjiu-ningzuowo/p/11774265.html