Android HandlerThread详解(源码分析)

目录:
目录

1. 前言

本篇文章是对 Android HandlerThread 类的学习,通过简单的例子,及分析源码来深入学习。同时例子将以 Java & Kotlin 两种代码形式展示。

1.1 定义

HandlerThread: 一个拥有 Looper 对象的线程。

继承于 Thread 类,并拥有一个 Looper 对象,可以利用该 Looper 对象来创建 Handler 对象,就像正常的线程一样,通过调用 start() 方法来开启线程。

1.2 使用场景

适用于子线程多任务的工作场景。如:在工作线程中进行多个网络请求,多个I/O操作,最典型的应用就是 IntentService,关于 IntentService 可以参考我的另一篇文章Android IntentService详解(源码分析)

2. 使用方法

其使用方法很简单:

  1. 在主线程中新建一个 HandlerThread 对象,然后调用 start() 方法启动该线程。
  2. 创建一个主线程Handler 对象,关联APP主Looper对象,用于子线程与主线程之间的沟通。
  3. 创建一个工作线程Handler 对象,关联 HandlerThread 的 Looper 对象。
  4. 发送消息给工作线程,工作线程Handler 接收消息,并处理消息,然后调用主线程。Handler,发送信息给主线程,通知主线程做UI工作。
  5. 当对应的 Activity 销毁时,退出 HandlerThread,终止消息循环。

比如:我们用两个 ProgressBar 来模拟在子线程中进行下载任务,点击按钮开始下载,ProgressBar 的进度代表着下载进度。
如下所示:

子线程执行多任务

2.1 Java版本

具体代码如下:

public class HandlerThreadActivity extends AppCompatActivity {
    private final int SET_PROGRESS_BAR_1 = 1;
    private final int SET_PROGRESS_BAR_2 = 2;
    private HandlerThread myHandlerThread;
    private Handler mWorkHandler, mMainHandler;
    private ProgressBar progressBar1, progressBar2;

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

        TextView titleTv = findViewById(R.id.title_tv);
        titleTv.setText("HandlerThread");

        progressBar1 = findViewById(R.id.progress_bar_1);
        progressBar2 = findViewById(R.id.progress_bar_2);
        Button startBtn1 = findViewById(R.id.start_progress_bar_1_btn);
        Button startBtn2 = findViewById(R.id.start_progress_bar_2_btn);

        //创建HandlerThread对象
        myHandlerThread = new HandlerThread("myHandlerThread");
        //启动线程
        myHandlerThread.start();

        //创建主线程Handler,关联APP的主Looper对象
        mMainHandler = new Handler(getMainLooper());

        //创建工作线程Handler,关联HandlerThread的Looper对象,所以它无法与主线程通讯
        mWorkHandler = new Handler(myHandlerThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);

                switch (msg.what) {
                    case SET_PROGRESS_BAR_1:
                        //设置Progress Bar 1
                        for (int i = 1; i <= 4; i++) {
                            try {
                                //模拟耗时工作
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }

                            final int progressSchedule = i;
                            //在工作线程中,通过主线程Handler, 传递信息给主线程,通知主线程处理UI工作。
                            mMainHandler.post(new Runnable() {
                                @Override
                                public void run() {
                                    progressBar1.setProgress(progressSchedule);
                                }
                            });
                        }
                        break;
                    case SET_PROGRESS_BAR_2:
                        //设置Progress Bar 2
                        for (int i = 1; i <= 4; i++) {
                            try {
                                //模拟耗时工作
                                Thread.sleep(1300);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }

                            final int progressSchedule2 = i;
                            //在工作线程中,通过主线程Handler, 传递信息给主线程,通知主线程处理UI工作。
                            mMainHandler.post(new Runnable() {
                                @Override
                                public void run() {
                                    progressBar2.setProgress(progressSchedule2);
                                }
                            });
                        }
                        break;
                    default:
                        break;
                }
            }
        };

        startBtn1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //通过工作线程Handler,mWorkHandler发送处理 progress bar 1 的信息给工作线程。
                Message msg = new Message();
                msg.what = SET_PROGRESS_BAR_1;
                mWorkHandler.sendMessage(msg);
            }
        });

        startBtn2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //通过工作线程Handler mWorkHandler发送处理 progress bar 2 的信息给工作线程。
                Message msg = new Message();
                msg.what = SET_PROGRESS_BAR_2;
                mWorkHandler.sendMessage(msg);
            }
        });

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        myHandlerThread.quit();
    }
}

2.2 Kotlin版本

Kotlin 版本代码如下:

class TestHandlerThreadActivity : AppCompatActivity(), View.OnClickListener {
    private lateinit var mHandlerThread: HandlerThread
    private lateinit var mMainHandler: Handler
    private lateinit var mWorkHandler: WorkHandler

    override fun onClick(v: View?) {
        when (v?.id) {
            R.id.handlerThreadStart1Btn -> mWorkHandler.obtainMessage(1).sendToTarget()
            R.id.handlerThreadStart2Btn -> mWorkHandler.obtainMessage(2).sendToTarget()
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test_handler_thread)

        mMainHandler = Handler(Looper.getMainLooper())

        mHandlerThread = HandlerThread("JereTest")
        mHandlerThread.start()
        mWorkHandler = WorkHandler(mHandlerThread.looper)

        handlerThreadStart1Btn.setOnClickListener(this)
        handlerThreadStart2Btn.setOnClickListener(this)
    }

    inner class WorkHandler(looper: Looper) : Handler(looper) {

        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)
            when (msg.what) {
                1 -> {
                    for (i in 1..5) {
                        Thread.sleep(1000)
                        mMainHandler.post { handlerThreadProgressBar1.progress = i }
                    }
                }
                2 -> {
                    for (j in 1..5) {
                        Thread.sleep(1000)
                        mMainHandler.post { handlerThreadProgressBar2.progress = j }
                    }
                }
            }
        }

    }

    override fun onDestroy() {
        super.onDestroy()
        mHandlerThread.quit()
    }

}

3. 源码分析

按使用步骤来分析源码:
HandlerThread使用方法

步骤一:在主线程中新建一个 HandlerThread 对象,然后调用 start() 方法启动该线程。

//创建 HandlerThread 对象
myHandlerThread = new HandlerThread("myHandlerThread");
//启动线程,执行 run() 方法
myHandlerThread.start();

//创建 HandlerThread 对象,看其构造函数
/**
 * HandlerThread的构造函数
 * @param name,线程名字是我们传入的,用于标记改线程
 */
public HandlerThread(String name) {
    super(name);
    //指定该线程的优先级为标准线程优先级
    mPriority = Process.THREAD_PRIORITY_DEFAULT;
}

//启动线程
@Override
public void run() {
    //获得线程标识符
    mTid = Process.myTid();
    //为该线程创建一个 Looper 对象,具体见下:
    Looper.prepare();
    synchronized (this) {
        //获取通过 Looper.prepare() 方法创建的 Looper 对象。
        mLooper = Looper.myLooper();
        //唤醒那些为创建Looper对象而阻塞的线程
        notifyAll();
    }
    //设置该线程的优先级,比如设置为标准线程优先级
    Process.setThreadPriority(mPriority);
    //消息循环前做的处理,即:如果想在消息循环前做一些处理,则需要复写onLooperPreopared()方法。
    onLooperPrepared();
    //循环该Looper对象中的消息队列
    Looper.loop();
    mTid = -1;
}

步骤二:创建一个主线程Handler 对象,关联APP主Looper对象,用于子线程与主线程之间的沟通。

//创建主线程Handler,关联APP的主Looper对象
mMainHandler = new Handler(getMainLooper());

其具体源码分析内容请看另外一篇文章Android Handler 深入学习及源码分析

步骤三. 创建一个工作线程Handler 对象,关联 HandlerThread 的 Looper 对象。
其具体实现方法如下:

//创建工作线程Handler,关联HandlerThread的Looper对象,所以它无法与主线程通讯
mWorkHandler = new Handler(myHandlerThread.getLooper()) {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
            ···略···
    }
};

通过 getLooper() 方法获取 HandlerThread 的 Looper 对象,其源码如下:

/**
 * 该方法返回该线程所关联的Looper对象。
 * 如果这个线程没有启动,或者由于任何原因isAlive()返回false,那么这个方法将返回null。
 * 如果这个线程已经启动,这个方法将阻塞,直到looper被初始化。
 * @return The looper.
 */
public Looper getLooper() {
    //线程未激活,返回 null
    if (!isAlive()) {
        return null;
    }
    
    //如果该线程已经启动,则阻塞该方法,直到创建好Looper对象。
    synchronized (this) {
        while (isAlive() && mLooper == null) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
    }
    return mLooper;
}

步骤四:发送消息给工作线程,工作线程Handler 接收消息,并处理消息,然后调用主线程Handler,发送信息给主线程,通知主线程做UI工作。
Handler 通过 sendMessage(Msg) 及 post(Runnable) 方法传递消息,本篇博客不展开具体分析,具体源代码分析见上一篇博客Android Handler 深入学习及源码分析

步骤五:当对应的 Activity 销毁时,退出 HandlerThread,终止消息循环。
当当前 Activity 退出销毁时,复写 onDestry() 方法,退出 HandlerThread,如:

@Override
protected void onDestroy() {
    super.onDestroy();
    myHandlerThread.quit();
}

通过 quit() 方法退出 HandlerThread,终止消息循环,具体源代码分析,见下:

/**
 * 终止 Handler 关联的 looper 消息循环,不在处理消息队列中的任何消息。
 * 当 looper 被停止后再尝试请求消息入消息队列,会失败,比如:sendMessage(Message) 会返回 false。
 * 使用该方法可能不安全,因为 looper 在没有循环分发完所有消息时就被停止了。
 * 考虑使用quitsafe() 方法来代替,以确保所有未完成的工作以有序的方式完成。
 *
 * @return 如果Looper停止消息循环,返回True; 如果线程尚未开始运行,则返回false。
 */
public boolean quit() {
    //获取 Handler 所关联的 Looper 对象。
    Looper looper = getLooper();
    //如果 Looper 不为空,停止其消息循环,返回true
    if (looper != null) {
        looper.quit();
        return true;
    }
    //如果 Looper 为空,即线程还未开始运行,返回 false。
    return false;
}

/**
 * 安全的终止 Handler 关联的 Looper 消息循环,处理消息队列中所有已到期的消息,而未到期的挂起的延迟消息将不被传递
 * 处理完消息队列中的所有消息后立即停止 Looper 消息循环
 * 当 looper 被停止后再尝试请求消息入消息队列,会失败,比如:sendMessage(Message) 会返回 false。
 * 如果线程还未开始或已经结束(getLooper 返回 null),返回false;另外,当 Looper 被要求 quit() 停止消息循环时,返回true。
 *
 * @return 如果Looper停止消息循环,返回True; 如果线程尚未开始运行,则返回false。
 */
public boolean quitSafely() {
    Looper looper = getLooper();
    if (looper != null) {
        //
        looper.quitSafely();
        return true;
    }
    return false;
}

至此 HandlerThread 的源码也就分析结束了。
其实分享文章的最大目的正是等待着有人指出我的错误,如果你发现哪里有错误,请毫无保留的指出即可,虚心请教。

另外,如果你觉得文章不错,对你有所帮助,请给我点个赞,就当鼓励,谢谢~Peace~!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值