第5章 多线程 - HandlerThread

优质
小牛编辑
123浏览
2023-12-01

继承自Thread,在run()方法中,执行了Looper.prepare()和Looper.loop(),和handler结合使用,实现后台轮询线程功能

  • start()
  • quit()
  • getLooper()
  1. public class HandlerThreadActivity extends AppCompatActivity {
  2. private TextView mTvServiceInfo;
  3. private HandlerThread mCheckMsgThread;
  4. private Handler mCheckMsgHandler;
  5. private boolean isUpdateInfo;
  6. private static final int MSG_UPDATE_INFO = 0x110;
  7. //与UI线程相关的handler
  8. private Handler mHandler = new Handler();
  9. @Override
  10. protected void onCreate(Bundle savedInstanceState) {
  11. super.onCreate(savedInstanceState);
  12. setContentView(R.layout.activity_thread_handler);
  13. initBackThread();//创建后台线程
  14. mTvServiceInfo = (TextView) findViewById(R.id.id_textview);
  15. }
  16. @Override
  17. protected void onResume() {
  18. super.onResume();
  19. isUpdateInfo = true;//开始查询
  20. mCheckMsgHandler.sendEmptyMessage(MSG_UPDATE_INFO);
  21. }
  22. @Override
  23. protected void onPause() {
  24. super.onPause();
  25. isUpdateInfo = false;//停止查询
  26. mCheckMsgHandler.removeMessages(MSG_UPDATE_INFO);
  27. }
  28. private void initBackThread() {
  29. mCheckMsgThread = new HandlerThread("check-message-coming");
  30. mCheckMsgThread.start();
  31. mCheckMsgHandler = new Handler(mCheckMsgThread.getLooper()) {
  32. @Override
  33. public void handleMessage(Message msg) {
  34. checkForUpdate();
  35. if (isUpdateInfo) {
  36. mCheckMsgHandler.sendEmptyMessageDelayed(
  37. MSG_UPDATE_INFO, 1000);
  38. }
  39. }
  40. };
  41. }
  42. //模拟从服务器解析数据
  43. private void checkForUpdate() {
  44. Thread.sleep(1000);//模拟耗时
  45. mHandler.post(new Runnable() {
  46. @Override
  47. public void run() {
  48. String result = "msg";
  49. mTvServiceInfo.setText(result);
  50. }
  51. });
  52. }
  53. @Override
  54. protected void onDestroy() {
  55. super.onDestroy();
  56. mCheckMsgThread.quit();//释放资源
  57. }
  58. }

2. HandlerThread源码

Handler的构造,其实就是在Handler中持有一个指向该Looper.mQueue对象,当handler调用sendMessage方法时,其实就是往该mQueue中去插入一个message,然后Looper.loop()就会取出执行

  1. public class HandlerThread extends Thread {
  2. int mPriority;
  3. int mTid = -1;
  4. Looper mLooper;
  5. public HandlerThread(String name) {
  6. super(name);
  7. mPriority = Process.THREAD_PRIORITY_DEFAULT;
  8. }
  9. public HandlerThread(String name, int priority) {
  10. super(name);
  11. mPriority = priority;
  12. }
  13. protected void onLooperPrepared() {
  14. }
  15. @Override
  16. public void run() {
  17. mTid = Process.myTid();
  18. Looper.prepare();
  19. synchronized (this) {
  20. mLooper = Looper.myLooper();
  21. notifyAll();
  22. }
  23. Process.setThreadPriority(mPriority);
  24. onLooperPrepared();
  25. Looper.loop();
  26. mTid = -1;
  27. }
  28. public Looper getLooper() {
  29. if (!isAlive()) {
  30. return null;
  31. }
  32. // If the thread has been started, wait until the looper has been created.
  33. synchronized (this) {
  34. while (isAlive() && mLooper == null) {
  35. try {
  36. wait();
  37. } catch (InterruptedException e) {
  38. }
  39. }
  40. }
  41. return mLooper;
  42. }
  43. public boolean quit() {
  44. Looper looper = getLooper();
  45. if (looper != null) {
  46. looper.quit();
  47. return true;
  48. }
  49. return false;
  50. }
  51. public boolean quitSafely() {
  52. Looper looper = getLooper();
  53. if (looper != null) {
  54. looper.quitSafely();
  55. return true;
  56. }
  57. return false;
  58. }
  59. public int getThreadId() {
  60. return mTid;
  61. }
  62. }

我们要在子线程中调用Looper.prepare() 为一个线程开启一个消息循环,默认情况下Android中新诞生的线程是没有开启消息循环的。(主线程除外,主线程系统会自动为其创建Looper对象,开启消息循环。) Looper对象通过MessageQueue来存放消息和事件。一个线程只能有一个Looper,对应一个MessageQueue。 然后通过Looper.loop() 让Looper开始工作,从消息队列里取消息,处理消息。

注意:写在Looper.loop()之后的代码不会被执行,这个函数内部应该是一个循环,当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。

3. HandlerThread的特点

  • HandlerThread将loop转到子线程中处理,说白了就是将分担MainLooper的工作量,降低了主线程的压力,使主界面更流畅。

  • 开启一个线程起到多个线程的作用。处理任务是串行执行,按消息发送顺序进行处理。HandlerThread本质是一个线程,在线程内部,代码是串行处理的。

  • 但是由于每一个任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理。

  • HandlerThread拥有自己的消息队列,它不会干扰或阻塞UI线程。

  • 对于网络IO操作,HandlerThread并不适合,因为它只有一个线程,还得排队一个一个等着。

4. 参考

详解 Android 中的 HandlerThread