亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Android消息機制原理深入分析

 更新時間:2022年12月09日 15:51:33   作者:Hdnw  
這篇文章主要介紹了Android消息機制原理,Android的消息機制主要是指Handler的運行機制以及Handler所附帶的MessageQueue和Looper的工作過程

1.消息機制原理的解釋

在主線程里創(chuàng)建一個Handler,然后在分線程中引用這個Handler來發(fā)送Message對象給MessageQueue,循環(huán)器Looper從MessageQueue里面取出一個需要處理的Message,交給Handler處理,一般是進行UI處理。處理完之后,Message就沒有太大的用處,Looper清理Message,讓Message回到默認狀態(tài)。

2.Android的消息機制概述

Handler的背景(三個常見問題)

(1)Android為什么要提供Handler?

這是因為Android規(guī)定訪問UI只能在主線程中進行,如果在子線程中訪問UI,那么程序就會拋出異常,但是Android又建議不要在主線程中進行耗時操作,否則會導致線程無法響應即ANR,比如我們需要從服務(wù)器拉取一些信息并將其顯示在UI上,這個時候必須在子線程中進行拉取工作,拉取完畢后,不能在子線程上直接訪問UI,這時候通過Handler就可以將訪問UI的操作切換到主線程去執(zhí)行。

(2)系統(tǒng)為什么不允許在子線程中訪問UI呢?

這個因為Android的UI控件并不是線程安全的,如果在多線程中并發(fā)訪問可能會導致UI控件處于不可預期的狀態(tài)。

(3)為什么系統(tǒng)不對UI控件的訪問加上鎖機制呢?

缺點有兩個:

  • 加上鎖機制會讓UI訪問的邏輯變得復雜
  • 鎖機制會降低UI訪問的效率,因為鎖機制會阻塞某些線程的執(zhí)行

鑒于這兩個缺點,最簡單且高效的方法就是采用單線程模型來處理UI操作。

Handler的工作原理的解釋

子線程默認沒有Looper的,如果需要使用Handler,那么在Handler創(chuàng)建時就需要為線程創(chuàng)建Looper,利用Looper來構(gòu)建內(nèi)部的消息循環(huán)系統(tǒng),如果當前線程沒有Looper,那么就會報錯。Handler創(chuàng)建完畢之后,Handler通過post方法把一個Runnable傳到Looper中去處理,或者通過send方法發(fā)送消息,Looper會調(diào)用MessageQueue的enqueueMessage方法將消息發(fā)入消息隊列中,然后Looper不斷循環(huán)發(fā)現(xiàn)需要處理的消息之后,就會調(diào)用消息中的Runnable或者或者Handler的handleMessage方法,這樣一來,Handler中的業(yè)務(wù)邏輯就被切除到創(chuàng)建Handler所在的線程中去執(zhí)行。

3.消息機制的分析

1.了解Message

可理解為線程間通訊的數(shù)據(jù)單元,可通過message攜帶需要的數(shù)據(jù)

   創(chuàng)建Message的方法

val message:Message= Message()
val message1:Message=Message.obtain()//它利用了Message中消息池(sPool)

   封裝數(shù)據(jù):

int what:標識

int arg1:保存int數(shù)據(jù)

int arg2:保存int數(shù)據(jù)

Object obj:保存任意時刻的數(shù)據(jù)

Long when :記錄應該被處理的時間值,若為即時消息,時間值=發(fā)送時間,若為延時消息,時間值=發(fā)送時間+延遲時間

Handler target:用來處理消息的Handler對象,就是發(fā)送消息的Handler

Runnable callback:用來處理消息的回調(diào)器

Message next:指向下一個Message用來形成一個鏈表

Message sPool:用來緩存處理過的Message,以便復用

2.了解Handler

Handler是Message的處理器,同時也負責消息的發(fā)送和移除的工作

(1)Handler的構(gòu)造方法

Android API 30以上,使用Handler()方法時會顯示刪除線,并提示相關(guān)的方法已經(jīng)被棄用,不建議使用。如圖所示:

但是安卓不是棄用Handler這個類,而只是棄用Handler的兩個構(gòu)造方法:

Handler()
Handler(callback:Handler.Callback)

 安卓建議采用如下方法來解決

1.使用Executor

2.明確指定Looper

3.使用Looper.getMainLooper()定位并使用主線程的Looper

4.如果又想在其他線程,又想要不出bug,請使用Handler(looper:Looper)或者Handler(Looper.myLooper())這兩個構(gòu)造方法。

(2) Handler導致的內(nèi)存泄漏問題

在Android中最常用的一種內(nèi)存泄漏是Handler導致的泄漏,原因:

(1)在Activity被摧毀時,延遲消息還沒發(fā)出,Handler可能有未執(zhí)行完或者正在執(zhí)行的Message,MessagesQueue就會持有這個消息的引用,導致Handler持有Activity的引用,進而導致GC無法回收Activity。

(2)Handler中有還沒執(zhí)行完的Message,還在運行,而運行中的子線程不會被回收,所以就導致了內(nèi)存泄漏。

解決方法:

1.在Activity的onDestroy()方法中,清空Handler中的未執(zhí)行或者正在執(zhí)行的Message和Callbacks

override fun onDestroy() {
        super.onDestroy()
        handler.removeCallbacksAndMessages(null)
    }

2.static+弱引用

class  MyHandler(activity: HandlerActivity):Handler(Looper.getMainLooper()){
        private val myWeakReference:WeakReference<HandlerActivity> = WeakReference(activity)
        override fun handleMessage(msg: Message) {//處理消息的回調(diào)方法
            myWeakReference.get()?.run {
            ...
        }
      }
 }

(3)Handler的常用方法:

  • 發(fā)送即時消息:sendMessage(msg  Message)
  • 發(fā)送延時消息:sendMessageDelayed(msg Message,delayMillis Long)
  • 處理方法:handleMessage(msg Message)(回調(diào)方法)
  • 移除還未處理的消息:removeMessages(what int)

部分源碼:

由下面的源碼可以看出,這些方法的本質(zhì)是調(diào)用了queue.enqueueMessage(msg,uptimeMillis)方法。

sendMessage(Message msg)
    ->sendMessageDelayed(msg,0)
sendEmptyMessage(int what)
    ->sendEmptyMessageDelayed(what,0)
sendEmptyMessageDelayed(what,0)//發(fā)送不帶數(shù)據(jù)的消息
     ->sendMessageDelayed(msg,delayMillis)
sendMessageDelayed(Message msg,long delayMillis)
     ->sendMessageAtTime(msg,SystemClock.uptimeMillis()+delayMillis)
sendMessageAtTime(Message msg,long uptimeMillis)
     ->enaueueMessage(queue,msg,uptimeMillis)//將消息添加到消息隊列中
enaueueMessage(MessageQueue queue,Message msg,long uptimeMillis)
     ->queue.enqueueMessage(msg,uptimeMillis)//調(diào)用消息隊列保存消息對象
removeMessage(int what)//移除消息
     ->mQueue.removeMessage(this,what,null)//調(diào)用消息隊列移除它內(nèi)部的指定what消息
handleMessage(Message msg)//處理消息的回調(diào)方法

3.消息隊列的工作原理

MessageQueue消息隊列,負責入隊和出隊,儲存Handler發(fā)送的消息,它是一個按Message的when的排序的優(yōu)先隊列。
雖然MessageQueue叫消息隊列,但是它內(nèi)部是用鏈表來實現(xiàn)的。

MessageQueue主要包含兩個操作:插入和讀取,讀取操作本身會伴隨刪除操作,插入和讀取對應的方法分別為enqueueMessage和next:

boolean enqueueMessage(Message msg, long when):往消息隊列中插入一條消息
Message next() :消息隊列中取出一條消息并將其從消息隊列中移除

enqueueMessage和 next方法的部分源碼:

enqueueMessage的主要操作就是單鏈表的插入操作

boolean enqueueMessage(Message msg, long when) {//將Messages插入消息隊列
    ...
   msg.when = when;//指定消息應該被處理的時間
   ...
   for (;;) {//將當前消息對象保存到消息隊列中的一個合適的位置
            prev = p;
            p = p.next;
            if (p == null || when < p.when) {
                break;
            }
            if (needWake && p.isAsynchronous()) {
                 needWake = false;
             }
    }//最終的結(jié)果是:消息隊列是按when來排序的
    ...
    nativeWake(mPtr);//通過本地方法實現(xiàn)對處理等待狀態(tài)的底層線程
    ...
}

 next方法是一個無限循環(huán)的方法。如果消息隊列中沒有消息,那么next方法可以阻塞在這里,

當有新的消息到來時,next方法會返回這條消息并將其中單鏈表中移除。

Message next() {//取出一個合適的Message對象,可能不會立刻返回
    ...
    nativePollOnce(ptr, nextPollTimeoutMillis);//本地方法,會導致可能處理等待狀態(tài),但不會阻塞主線程
    ...
    Message msg = mMessages;//取出消息隊列中的第一個消息
    ...
    return msg;//返回
    ...
}

4.Looper的工作原理

Looper在Android的消息機制中扮演著消息循環(huán)的角色。

Looper為一個線程開啟一個消息循環(huán),創(chuàng)建MessageQueue,負責循環(huán)取出Message Queue里面的當前需要處理的Message,也就是說,它會一直不停地從MessageQueue中查看是否會有新消息,如果有新消息就會交給對應的Handler進行處理,處理完后,將Message緩存到消息池中以備復用,否則就一直阻塞在那里,Looper退出后,Handler發(fā)送消息會失敗,線程會立刻終止。

常用方法:?

Looper.prepare():為當前線程創(chuàng)建一個Looper。

Looper.loop():開啟消息循環(huán).

Looper.getMainLooper():獲取主線程的Looper。

Looper.quit()直接推遲Looper

Looper.quitSafely()設(shè)定一個退出標記,然后把消息隊列中的已有消息處理完畢才安全地退出。

如何為一個線程創(chuàng)建Looper?

thread {
            Looper.prepare()
            val  handler:Handler=MyHandler(this)
            Looper.loop()
        }

 loop方法的部分源碼:

 public static void loop() {
    final Looper me = myLooper();//得到looper對象
    ...
    for (;;) {//無限循環(huán)
         ...
         Message msg = me.mQueue.next(); // 從消息隊列中取出消息
         ...
         msg.target.dispatchMessage(msg);//調(diào)用Handler去分發(fā)并處理消息
         ...
         msg.recycleUnchecked();//回收利用Message
         ...
    }
}

4.Handler使用(DEMO)

功能描述:

1.初始時

顯示10,可以通過點擊按鈕改變其值

2.點擊自動增加

每隔一秒上面的文本數(shù)值增加1,但最大顯示20并作出提示

3.點擊自動減少

每隔一秒上面的文本數(shù)值減少1,但是最小顯示1并作出提示

4.點擊暫停

上面的數(shù)值文本不再變化

效果圖:

代碼如下:

class HandlerActivity : AppCompatActivity() {
    lateinit var handler: Handler
    lateinit var number:TextView
    lateinit var increase:Button
    lateinit var decrease:Button
    lateinit var pause:Button
    //static+弱引用
    class  MyHandler(activity: HandlerActivity):Handler(Looper.getMainLooper()){
        private val myWeakReference:WeakReference<HandlerActivity> = WeakReference(activity)
        override fun handleMessage(msg: Message) {//處理消息的回調(diào)方法
            myWeakReference.get()?.run {
                var numberint:Int=Integer.parseInt(number.text.toString())
                when(msg.what){
                    1->{
                        if(numberint==20){
                            Toast.makeText(this,"已經(jīng)達到最大值",Toast.LENGTH_SHORT).show()
                             return
                        }
                        numberint++
                        number.text= numberint.toString()
                        handler.sendEmptyMessageDelayed(1,1000)
                    }
                    2->{
                        if(numberint==1){
                            Toast.makeText(this,"已經(jīng)達到最小值",Toast.LENGTH_SHORT).show()
                            return
                        }
                        numberint--
                        number.text=numberint.toString()
                        handler.sendEmptyMessageDelayed(2,1000)
                    }
                    else -> {}
                }
            }
        }
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_handler)
        number=findViewById(R.id.number)
        increase=findViewById(R.id.increase)
        decrease=findViewById(R.id.decrease)
        pause=findViewById(R.id.pause)
        handler=MyHandler(this)
        increase.setOnClickListener {
            increase.isEnabled=false
            decrease.isEnabled=true
            pause.isEnabled=true
            handler.removeMessages(2)
            handler.sendEmptyMessage(1)
        }
        decrease.setOnClickListener {
            increase.isEnabled=true
            decrease.isEnabled=false
            pause.isEnabled=true
            handler.removeMessages(1)
            handler.sendEmptyMessage(2)
        }
        pause.setOnClickListener {
            increase.isEnabled=true
            decrease.isEnabled=true
            pause.isEnabled=false
            handler.removeMessages(1)
            handler.removeMessages(2)
        }
    }
    override fun onDestroy() {
        super.onDestroy()
        handler.removeCallbacksAndMessages(null)
    }
}

到此這篇關(guān)于Android消息機制原理深入分析的文章就介紹到這了,更多相關(guān)Android消息機制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • android intent使用定義標題

    android intent使用定義標題

    本文將詳細介紹android怎樣自定義Intent選擇界面的標題,提供相關(guān)參考方法
    2012-11-11
  • android打開rar壓縮文件

    android打開rar壓縮文件

    這篇文章主要介紹了android打開rar壓縮文件示例,調(diào)用RAR for android 打開壓縮文件,需要的朋友可以參考下
    2014-03-03
  • Android廣播機制原理與開發(fā)

    Android廣播機制原理與開發(fā)

    Android廣播機制就是在Android中,有一些操作完成以后,會發(fā)送廣播,比如說發(fā)出一條短信,或打出一個電話,如果某個程序接收了這個廣播,就會做相應的處理
    2023-02-02
  • Android學習系列一用按鈕實現(xiàn)顯示時間

    Android學習系列一用按鈕實現(xiàn)顯示時間

    這篇文章主要介紹了Android學習系列一用按鈕實現(xiàn)顯示時間的相關(guān)資料,需要的朋友可以參考下
    2016-05-05
  • Android APK反編譯圖文教程

    Android APK反編譯圖文教程

    學會反編譯比較關(guān)鍵,也是我們美化必須掌握技術(shù),學會反編譯也是實現(xiàn)制作ROM的起步,ROM高手必然是反編譯高手這里有必要說一下,教程只是給你一個動手的那一個蹺板,教程不是萬能的,給了你基礎(chǔ)與啟發(fā),最重要的是我們能夠自主的進行創(chuàng)新與思考
    2016-04-04
  • 詳解Android 在 ViewPager 中使用 Fragment 的懶加載

    詳解Android 在 ViewPager 中使用 Fragment 的懶加載

    本篇文章主要介紹了Android 在 ViewPager 中使用 Fragment 的懶加載,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • Android ActionBar完全解析使用官方推薦的最佳導航欄(下)

    Android ActionBar完全解析使用官方推薦的最佳導航欄(下)

    這篇文章主要介紹了Android ActionBar完全解析使用官方推薦的最佳導航欄(下) ,需要的朋友可以參考下
    2017-04-04
  • Android控件Tween動畫(補間動畫)實現(xiàn)方法示例

    Android控件Tween動畫(補間動畫)實現(xiàn)方法示例

    這篇文章主要介紹了Android控件Tween動畫(補間動畫)實現(xiàn)方法,結(jié)合具體實例形式分析了Android補間動畫的原理、功能實現(xiàn)與布局相關(guān)操作技巧,需要的朋友可以參考下
    2017-08-08
  • Android使用URL讀取網(wǎng)絡(luò)資源的方法

    Android使用URL讀取網(wǎng)絡(luò)資源的方法

    這篇文章主要為大家詳細介紹了Android使用URL讀取網(wǎng)絡(luò)資源的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • Android使用lottie加載json動畫的示例代碼

    Android使用lottie加載json動畫的示例代碼

    本篇文章主要介紹了Android使用lottie加載json動畫的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01

最新評論