歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Android中HandlerThread類的解析

Android中HandlerThread類的解析

日期:2017/3/1 10:13:06   编辑:Linux編程

Android應用中的消息循環由Looper和Handler配合完成,Looper類用於封裝消息循環,類中有個MessageQueue消息隊列;Handler類封裝了消息投遞和消息處理等功能。

系統默認情況下只有主線程(即UI線程)綁定Looper對象,因此在主線程中可以直接創建Handler的實例,但是在子線程中就不能直接new出Handler的實例了,因為子線程默認並沒有Looper對象,此時會拋出RuntimeException異常:

浏覽下Handler的默認構造函數就一目了然了:

  1. public Handler() {
  2. if (FIND_POTENTIAL_LEAKS) {
  3. final Class<? extends Handler> klass = getClass();
  4. if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
  5. (klass.getModifiers() & Modifier.STATIC) == 0) {
  6. Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
  7. klass.getCanonicalName());
  8. }
  9. }
  10. mLooper = Looper.myLooper();
  11. if (mLooper == null) {
  12. throw new RuntimeException(
  13. "Can't create handler inside thread that has not called Looper.prepare()");
  14. }
  15. mQueue = mLooper.mQueue;
  16. mCallback = null;
  17. }

如果需要在子線程中使用Handler類,首先需要創建Looper類實例,這時可以通過Looper.prepare()和Looper.loop()函數來實現的。閱讀Framework層源碼發現,Android為我們提供了一個HandlerThread類,該類繼承Thread類,並使用上面兩個函數創建Looper對象,而且使用wait/notifyAll解決了多線程中子線程1獲取子線程2的Looper對象為空的問題。HandlerThread類完整代碼如下:

  1. /**
  2. * Handy class for starting a new thread that has a looper. The looper can then
  3. * be used to create handler classes. Note that start() must still be called.
  4. */
  5. public class HandlerThread extends Thread {
  6. private int mPriority; // 線程優先級
  7. private int mTid = -1; // 線程ID
  8. private Looper mLooper; // 我們需要的Looper對象
  9. public HandlerThread(String name) {
  10. super(name);
  11. mPriority = Process.THREAD_PRIORITY_DEFAULT;
  12. }
  13. /**
  14. * Constructs a HandlerThread.
  15. *
  16. * @param name
  17. * @param priority
  18. * The priority to run the thread at. The value supplied must be
  19. * from {@link android.os.Process} and not from java.lang.Thread.
  20. */
  21. public HandlerThread(String name, int priority) {
  22. super(name);
  23. mPriority = priority;
  24. }
  25. /**
  26. * 在Looper.loop()之前執行動作的回調函數
  27. */
  28. protected void onLooperPrepared() {
  29. }
  30. public void run() {
  31. mTid = Process.myTid();
  32. Looper.prepare(); // 創建本線程的Looper對象
  33. synchronized (this) {
  34. mLooper = Looper.myLooper();
  35. notifyAll(); //通知所有等待該線程Looper對象的其他子線程,本線程的Looper對象已就緒
  36. }
  37. Process.setThreadPriority(mPriority);
  38. onLooperPrepared(); //回調函數
  39. Looper.loop(); //開始消息隊列循環
  40. mTid = -1;
  41. }
  42. /**
  43. * This method returns the Looper associated with this thread. If this
  44. * thread not been started or for any reason is isAlive() returns false,
  45. * this method will return null. If this thread has been started, this
  46. * method will block until the looper has been initialized.
  47. *
  48. * @return The looper.
  49. */
  50. public Looper getLooper() {
  51. if (!isAlive()) {
  52. return null;
  53. }
  54. // If the thread has been started, wait until the looper has been
  55. // created.
  56. synchronized (this) {
  57. while (isAlive() && mLooper == null) {
  58. try {
  59. wait(); //Looper對象未創建好,等待
  60. } catch (InterruptedException e) {
  61. }
  62. }
  63. }
  64. return mLooper;
  65. }
  66. /**
  67. * Ask the currently running looper to quit. If the thread has not been
  68. * started or has finished (that is if {@link #getLooper} returns null),
  69. * then false is returned. Otherwise the looper is asked to quit and true is
  70. * returned.
  71. */
  72. public boolean quit() {
  73. Looper looper = getLooper();
  74. if (looper != null) {
  75. looper.quit();
  76. return true;
  77. }
  78. return false;
  79. }
  80. /**
  81. * Returns the identifier of this thread. See Process.myTid().
  82. */
  83. public int getThreadId() {
  84. return mTid;
  85. }
  86. }
Copyright © Linux教程網 All Rights Reserved