1. 程式人生 > >Android中關於項目中對Thread的管理(不是線程池)

Android中關於項目中對Thread的管理(不是線程池)

lan ole 問題 直接 per dma 之前 ron move

背景

項目中對於一些並不復雜的耗時操作,比如計算,不頻繁操作數據庫等,因為沒必要使用線程池,所以之前項目會直接使用new Thread的方式,時間一長,回頭再看,原來new Thread之處已經很多了,這樣帶來了一些問題:

  1. 不斷的new Thread,損耗性能。
  2. 在有生命周期的類(Activity或者Fragment或者Service)中,有可能出現內存泄漏。
  3. 缺乏統一管理,維護不方便。

分析

問題拋出了,就想辦法解決吧。對於任務量小,操作不那麽頻繁的,我們只需要放在一個後臺線程中即能滿足要求,思路是只需要分門別類就可以了,對於操作數據庫的,都使用data線程,對於計算相關的,都使用background線程,這樣整個項目只需要維護幾個固定後臺線程。

註意:

  1. data 和background都是線程的名字,可以自己添加或者定義。
  2. 因為項目中已經維護了自己封裝的線程池,所有涉及到下載,請求等大量I/O操作會使用線程池。

解決方案

自己封裝了ThreadManager。

  1. public class ThreadManager {
  2. /** 主線程 */
  3. public static final int THREAD_UI = 0;
  4. /** background線程,用於一般的耗時操作 */
  5. public static final int THREAD_BACKGROUND = 1;
  6. /** data線程,用於數據庫操作 */
  7. public static final int THREAD_DATA = 2;
  8. private static final int THREAD_SIZE = 3;
  9. /** 線程信息數組 */
  10. private static final Handler[] HANDLER_LIST = new Handler[THREAD_SIZE];
  11. private static final String[] THREAD_NAME_LIST = {
  12. "thread_ui",
  13. "thread_background",
  14. "thread_data"
  15. };
  16. private ThreadManager() {
  17. HANDLER_LIST[THREAD_UI] = new Handler();
  18. }
  19. private static class ThreadManagerHolder {
  20. private static ThreadManager sManager = new ThreadManager();
  21. }
  22. public static ThreadManager getManager() {
  23. return ThreadManagerHolder.sManager;
  24. }
  25. /**
  26. * 派發任務
  27. *
  28. * @param index 線程類型
  29. */
  30. public void post(int index, Runnable r) {
  31. postDelayed(index, r, 0);
  32. }
  33. /**
  34. * 延遲派發任務
  35. *
  36. * @param index 線程類型
  37. */
  38. public void postDelayed(int index, Runnable r, long delayMillis) {
  39. Handler handler = getHandler(index);
  40. handler.postDelayed(r, delayMillis);
  41. }
  42. /**
  43. * 刪除任務
  44. *
  45. * @param index 線程類型
  46. */
  47. public void removeCallbacks(int index, Runnable r) {
  48. Handler handler = getHandler(index);
  49. handler.removeCallbacks(r);
  50. }
  51. /**
  52. * 獲取線程Handler
  53. *
  54. * @param index 線程類型
  55. */
  56. public Handler getHandler(int index) {
  57. if (index < 0 || index >= THREAD_SIZE) {
  58. throw new InvalidParameterException();
  59. }
  60. if (HANDLER_LIST[index] == null) {
  61. synchronized (HANDLER_LIST) {
  62. if (HANDLER_LIST[index] == null) {
  63. HandlerThread thread = new HandlerThread(THREAD_NAME_LIST[index]);
  64. if (index != THREAD_UI) {
  65. //優先級要低於主線程
  66. thread.setPriority(Thread.MIN_PRIORITY);
  67. }
  68. thread.start();
  69. Handler handler = new Handler(thread.getLooper());
  70. HANDLER_LIST[index] = handler;
  71. }
  72. }
  73. }
  74. return HANDLER_LIST[index];
  75. }
  76. /**
  77. * 判斷是否運行在當前線程
  78. *
  79. * @param index 線程類型
  80. * @return true yes
  81. */
  82. public boolean runningOnCurrent(int index) {
  83. return getHandler(index).getLooper() == Looper.myLooper();
  84. }
  85. }

註釋一目了然,不做解釋。

來自:

背景

項目中對於一些並不復雜的耗時操作,比如計算,不頻繁操作數據庫等,因為沒必要使用線程池,所以之前項目會直接使用new Thread的方式,時間一長,回頭再看,原來new Thread之處已經很多了,這樣帶來了一些問題:

  1. 不斷的new Thread,損耗性能。
  2. 在有生命周期的類(Activity或者Fragment或者Service)中,有可能出現內存泄漏。
  3. 缺乏統一管理,維護不方便。

分析

問題拋出了,就想辦法解決吧。對於任務量小,操作不那麽頻繁的,我們只需要放在一個後臺線程中即能滿足要求,思路是只需要分門別類就可以了,對於操作數據庫的,都使用data線程,對於計算相關的,都使用background線程,這樣整個項目只需要維護幾個固定後臺線程。

註意:

  1. data 和background都是線程的名字,可以自己添加或者定義。
  2. 因為項目中已經維護了自己封裝的線程池,所有涉及到下載,請求等大量I/O操作會使用線程池。

解決方案

自己封裝了ThreadManager。

  1. public class ThreadManager {
  2. /** 主線程 */
  3. public static final int THREAD_UI = 0;
  4. /** background線程,用於一般的耗時操作 */
  5. public static final int THREAD_BACKGROUND = 1;
  6. /** data線程,用於數據庫操作 */
  7. public static final int THREAD_DATA = 2;
  8. private static final int THREAD_SIZE = 3;
  9. /** 線程信息數組 */
  10. private static final Handler[] HANDLER_LIST = new Handler[THREAD_SIZE];
  11. private static final String[] THREAD_NAME_LIST = {
  12. "thread_ui",
  13. "thread_background",
  14. "thread_data"
  15. };
  16. private ThreadManager() {
  17. HANDLER_LIST[THREAD_UI] = new Handler();
  18. }
  19. private static class ThreadManagerHolder {
  20. private static ThreadManager sManager = new ThreadManager();
  21. }
  22. public static ThreadManager getManager() {
  23. return ThreadManagerHolder.sManager;
  24. }
  25. /**
  26. * 派發任務
  27. *
  28. * @param index 線程類型
  29. */
  30. public void post(int index, Runnable r) {
  31. postDelayed(index, r, 0);
  32. }
  33. /**
  34. * 延遲派發任務
  35. *
  36. * @param index 線程類型
  37. */
  38. public void postDelayed(int index, Runnable r, long delayMillis) {
  39. Handler handler = getHandler(index);
  40. handler.postDelayed(r, delayMillis);
  41. }
  42. /**
  43. * 刪除任務
  44. *
  45. * @param index 線程類型
  46. */
  47. public void removeCallbacks(int index, Runnable r) {
  48. Handler handler = getHandler(index);
  49. handler.removeCallbacks(r);
  50. }
  51. /**
  52. * 獲取線程Handler
  53. *
  54. * @param index 線程類型
  55. */
  56. public Handler getHandler(int index) {
  57. if (index < 0 || index >= THREAD_SIZE) {
  58. throw new InvalidParameterException();
  59. }
  60. if (HANDLER_LIST[index] == null) {
  61. synchronized (HANDLER_LIST) {
  62. if (HANDLER_LIST[index] == null) {
  63. HandlerThread thread = new HandlerThread(THREAD_NAME_LIST[index]);
  64. if (index != THREAD_UI) {
  65. //優先級要低於主線程
  66. thread.setPriority(Thread.MIN_PRIORITY);
  67. }
  68. thread.start();
  69. Handler handler = new Handler(thread.getLooper());
  70. HANDLER_LIST[index] = handler;
  71. }
  72. }
  73. }
  74. return HANDLER_LIST[index];
  75. }
  76. /**
  77. * 判斷是否運行在當前線程
  78. *
  79. * @param index 線程類型
  80. * @return true yes
  81. */
  82. public boolean runningOnCurrent(int index) {
  83. return getHandler(index).getLooper() == Looper.myLooper();
  84. }
  85. }

註釋一目了然,不做解釋。

使用方法

技術分享

註意:

在綁定生命周期的api中使用,需要主動removeCallBacks,防止內存泄漏。

結語

以上就是關於項目中一些固定線程的封裝。

水平有限,如有不對之處,歡迎指出。

使用方法

技術分享

註意:

在綁定生命周期的api中使用,需要主動removeCallBacks,防止內存泄漏。

結語

以上就是關於項目中一些固定線程的封裝。

水平有限,如有不對之處,歡迎指出。

Android中關於項目中對Thread的管理(不是線程池)