自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

深入理解Android消息處理系統(tǒng)原理

移動開發(fā) Android
本文深入介紹Android消息處理系統(tǒng)原理,詳細(xì)講解了Android消息處理系統(tǒng):Looper、Handler、Thread的功能和處理機(jī)制。Android消息處理機(jī)制對于應(yīng)用程序開發(fā)非常重要,也可以讓你對線程同步有更加深刻的認(rèn)識。

Android應(yīng)用程序也是消息驅(qū)動的,按道理來說也應(yīng)該提供消息循環(huán)機(jī)制。實(shí)際上谷歌參考了Windows的消息循環(huán)機(jī)制,也在Android系統(tǒng)中實(shí)現(xiàn)了消息循環(huán)機(jī)制。

Android通過Looper、Handler來實(shí)現(xiàn)消息循環(huán)機(jī)制,Android消息循環(huán)是針對線程的(每個(gè)線程都可以有自己的消息隊(duì)列和消息循環(huán))。

本文深入介紹一下Android消息處理系統(tǒng)原理。

Android系統(tǒng)中Looper負(fù)責(zé)管理線程的消息隊(duì)列和消息循環(huán),具體實(shí)現(xiàn)請參考Looper的源碼。 可以通過Loop.myLooper()得到當(dāng)前線程的Looper對象,通過Loop.getMainLooper()可以獲得當(dāng)前進(jìn)程的主線程的Looper對象。

前面提到Android系統(tǒng)的消息隊(duì)列和消息循環(huán)都是針對具體線程的,一個(gè)線程可以存在(當(dāng)然也可以不存在)一個(gè)消息隊(duì)列 和一個(gè)消息循環(huán)(Looper),特定線程的消息只能分發(fā)給本線程,不能進(jìn)行跨線程,跨進(jìn)程通訊。但是創(chuàng)建的工作線程默認(rèn)是沒有消息循環(huán)和消息隊(duì)列的,如果想讓該線程具有消息隊(duì)列和消息循環(huán),需要在線程中首先調(diào)用Looper.prepare()來創(chuàng)建消息隊(duì)列,然后調(diào)用Looper.loop()進(jìn)入消息循環(huán)。如下例所示:

 

  1. class LooperThread extends Thread {  
  2.  
  3. public Handler mHandler;  
  4.  
  5. public void run() {  
  6.  
  7. Looper.prepare();  
  8.  
  9. mHandler = new Handler() {  
  10.  
  11. public void handleMessage(Message msg) {  
  12.  
  13. // process incoming messages here  
  14.  
  15. }  
  16.  
  17. };  
  18.  
  19. Looper.loop();  
  20.  
  21. }  
  22.  

 

這樣你的線程就具有了消息處理機(jī)制了,在Handler中進(jìn)行消息處理。

Activity是一個(gè)UI線程,運(yùn)行于主線程中,Android系統(tǒng)在啟動的時(shí)候會為Activity創(chuàng)建一個(gè)消息隊(duì)列和消息循環(huán)(Looper)。詳細(xì)實(shí)現(xiàn)請參考ActivityThread.java文件。

Handler的作用是把消息加入特定的(Looper)消息隊(duì)列中,并分發(fā)和處理該消息隊(duì)列中的消息。構(gòu)造Handler的時(shí)候可以指定一個(gè)Looper對象,如果不指定則利用當(dāng)前線程的Looper創(chuàng)建。詳細(xì)實(shí)現(xiàn)請參考Looper的源碼。

Activity、Looper、Handler的關(guān)系如下圖所示:

一個(gè)Activity中可以創(chuàng)建多個(gè)工作線程或者其他的組件,如果這些線程或者組件把他們的消息放入Activity的主線程消息隊(duì)列,那么該消息就會在 主線程中處理了。因?yàn)橹骶€程一般負(fù)責(zé)界面的更新操作,并且Android系統(tǒng)中的weget不是線程安全的,所以這種方式可以很好的實(shí)現(xiàn)Android界 面更新。在Android系統(tǒng)中這種方式有著廣泛的運(yùn)用。

那么另外一個(gè)線程怎樣把消息放入主線程的消息隊(duì)列呢?

答案是通過Handle對象,只要Handler對象以主線程的Looper創(chuàng)建,那么調(diào)用 Handler的sendMessage等接口,將會把消息放入隊(duì)列都將是放入主線程的消息隊(duì)列。并且將會在Handler主線程中調(diào)用該handler 的handleMessage接口來處理消息。

這里面涉及到線程同步問題,請先參考如下例子來理解Handler對象的線程模型:

1、首先創(chuàng)建MyHandler工程。

2、在MyHandler.java中加入如下的代碼:

 

  1. package com.simon;  
  2.  
  3. import android.app.Activity;  
  4.  
  5. import android.os.Bundle;  
  6.  
  7. import android.os.Message;  
  8.  
  9. import android.util.Log;  
  10.  
  11. import android.os.Handler;  
  12.  
  13. public class MyHandler extends Activity {  
  14.  
  15. static final String TAG = "Handler";  
  16.  
  17. Handler h = new Handler(){  
  18.  
  19. public void handleMessage (Message msg)  
  20.  
  21. {  
  22.  
  23. switch(msg.what)  
  24.  
  25. {  
  26.  
  27. case HANDLER_TEST:  
  28.  
  29. Log.d(TAG, "The handler thread id = " + Thread.currentThread().getId() + "\n");  
  30.  
  31. break;  
  32.  
  33. }  
  34.  
  35. }  
  36.  
  37. };  
  38.  
  39. static final int HANDLER_TEST = 1;  
  40.  
  41. /** Called when the activity is first created. */ 
  42.  
  43. @Override 
  44.  
  45. public void onCreate(Bundle savedInstanceState) {  
  46.  
  47. super.onCreate(savedInstanceState);  
  48.  
  49. Log.d(TAG, "The main thread id = " + Thread.currentThread().getId() + "\n");  
  50.  
  51. new myThread().start();  
  52.  
  53. setContentView(R.layout.main);  
  54.  
  55. }  
  56.  
  57. class myThread extends Thread  
  58.  
  59. {  
  60.  
  61. public void run()  
  62.  
  63. {  
  64.  
  65. Message msg = new Message();  
  66.  
  67. msg.what = HANDLER_TEST;  
  68.  
  69. h.sendMessage(msg);  
  70.  
  71. Log.d(TAG, "The worker thread id = " + Thread.currentThread().getId() + "\n");  
  72.  
  73. }  
  74.  
  75. }  
  76.  

 

在這個(gè)例子中我們主要是打印,這種處理機(jī)制各個(gè)模塊的所處的線程情況。如下是我的機(jī)器運(yùn)行結(jié)果:

09-10 23:40:51.478: DEBUG/Handler(302): The main thread id = 1 09-10 23:40:51.569: DEBUG/Handler(302): The worker thread id = 8 09-10 23:40:52.128: DEBUG/Handler(302): The handler thread id = 1

我們可以看出消息處理是在主線程中處理的,在消息處理函數(shù)中可以安全的調(diào)用主線程中的任何資源,包括刷新界面。工作線程和主線程運(yùn)行在不同的線程中,所以必須要注意這兩個(gè)線程間的競爭關(guān)系。

上例中,你可能注意到在工作線程中訪問了主線程handler對象,并在調(diào)用handler的對象向消息隊(duì)列加入了一個(gè)消息。這個(gè)過程中會不會出現(xiàn)消息隊(duì) 列數(shù)據(jù)不一致問題呢?答案是handler對象不會出問題,因?yàn)閔andler對象管理的Looper對象是線程安全的,不管是加入消息到消息隊(duì)列和從隊(duì) 列讀出消息都是有同步對象保護(hù)的,具體請參考Looper.java文件。上例中沒有修改handler對象,所以handler對象不可能會出現(xiàn)數(shù)據(jù)不 一致的問題。

通過上面的分析,我們可以得出如下結(jié)論:

1、如果通過工作線程刷新界面,推薦使用handler對象來實(shí)現(xiàn)。

2、注意工作線程和主線程之間的競爭關(guān)系。推薦handler對象在主線程中構(gòu)造完成(并且啟動工作線程之后不要再修改之,否則會出現(xiàn)數(shù)據(jù)不一致),然后在工作線程中可以放心的調(diào)用發(fā)送消息SendMessage等接口。

3、除了2所述的hanlder對象之外的任何主線程的成員變量如果在工作線程中調(diào)用,仔細(xì)考慮線程同步問題。如果有必要需要加入同步對象保護(hù)該變量。

4、handler對象的handleMessage接口將會在主線程中調(diào)用。在這個(gè)函數(shù)可以放心的調(diào)用主線程中任何變量和函數(shù),進(jìn)而完成更新UI的任務(wù)。

5、Android很多API也利用Handler這種線程特性,作為一種回調(diào)函數(shù)的變種,來通知調(diào)用者。這樣Android框架就可以在其線程中將消息發(fā)送到調(diào)用者的線程消息隊(duì)列之中,不用擔(dān)心線程同步的問題。

深入理解Android消息處理機(jī)制對于應(yīng)用程序開發(fā)非常重要,也可以讓你對線程同步有更加深刻的認(rèn)識。

【編輯推薦】

  1. Android學(xué)習(xí)筆記:Activity跳轉(zhuǎn)
  2. 官方文檔:Android應(yīng)用程序運(yùn)行的性能設(shè)計(jì)
  3. Android開發(fā):實(shí)現(xiàn)popupwindow中顯示listview
  4. Android開發(fā):實(shí)現(xiàn)帶圖片和checkbox的listview
責(zé)任編輯:佚名 來源: 博客園
相關(guān)推薦

2022-09-01 08:08:35

Android移動操作系統(tǒng)

2020-11-13 16:40:05

RocketMQ延遲消息架構(gòu)

2021-10-26 17:52:52

Android插件化技術(shù)

2022-11-04 09:43:05

Java線程

2024-03-12 00:00:00

Sora技術(shù)數(shù)據(jù)

2022-09-05 08:39:04

kubernetesk8s

2021-03-10 10:55:51

SpringJava代碼

2024-11-01 08:57:07

2020-08-10 18:03:54

Cache存儲器CPU

2024-04-15 00:00:00

技術(shù)Attention架構(gòu)

2021-09-10 07:31:54

AndroidAppStartup原理

2023-09-19 22:47:39

Java內(nèi)存

2022-09-26 08:01:31

線程LIFO操作方式

2022-01-14 12:28:18

架構(gòu)OpenFeign遠(yuǎn)程

2020-03-26 16:40:07

MySQL索引數(shù)據(jù)庫

2019-07-01 13:34:22

vue系統(tǒng)數(shù)據(jù)

2022-09-05 22:22:00

Stream操作對象

2020-03-17 08:36:22

數(shù)據(jù)庫存儲Mysql

2023-10-13 13:30:00

MySQL鎖機(jī)制

2020-11-04 15:35:13

Golang內(nèi)存程序員
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號