真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

android機(jī)制,安卓的機(jī)制

Android-消息機(jī)制

一共有四個(gè)角色,Handler消息處理者、Looper消息循環(huán)、MessageQueue消息隊(duì)列、Message消息。當(dāng)handler調(diào)用post或者sendMessage時(shí),最后都會(huì)調(diào)用內(nèi)部的sendMessageDelayed方法,再通過(guò)enqueueMessage方法,設(shè)置了msg.target并將消息加入MessageQueue,在MessageQueue中調(diào)用了nativeWake喚醒了next方法中的nativePollOnce。而Looper的loop方法此時(shí)因?yàn)镸essageQueue的next方法被阻塞著,直到next方法返回這條msg,Looper的loop調(diào)用了msg.target.diapatchMessage。到達(dá)了Handler 的事件分發(fā),進(jìn)行消息處理。

成都創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),梁溪企業(yè)網(wǎng)站建設(shè),梁溪品牌網(wǎng)站建設(shè),網(wǎng)站定制,梁溪網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營(yíng)銷,網(wǎng)絡(luò)優(yōu)化,梁溪網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競(jìng)爭(zhēng)力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶成長(zhǎng)自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。

從線程中取出myLooper的過(guò)程(字節(jié))

Looper.java

有一個(gè)static final變量sThreadLocal = new ThreadLocalLooper();

Looper.myLooper()是調(diào)用了sThreadLocal.get()

ThreadLocal.java

ThreadLocal.get()中獲取currentThread,

拿到Thread中的變量ThreadLocalMap,

Thread.java

變量ThreadLocal.ThreadLocalMap,數(shù)據(jù)被存在了該類中的Entry[] table

ThreadLocal.java

map.getEntry(this)-用和HashMap一樣的方式計(jì)算下標(biāo)(hashCode(table.len-1))

兩個(gè)變量合流,拿到了ThreadLocalMap.Entry,(Entry是ThreadLocal弱引用和value的鍵值對(duì)組合)

entry.value就是我們需要的Looper

在MessageQueue.next()里,如果頭部的這個(gè)Message是有延遲而且延遲時(shí)間沒(méi)到的(now msg.when),會(huì)計(jì)算一下時(shí)間(保存為變量nextPollTimeoutMillis),然后在循環(huán)開(kāi)始的時(shí)候判斷如果這個(gè)Message有延遲,就調(diào)用nativePollOnce(ptr, nextPollTimeoutMillis);進(jìn)行阻塞。nativePollOnce()的作用類似與object.wait(),只不過(guò)是使用了Native的方法對(duì)這個(gè)線程精確時(shí)間的喚醒。

postDelay()一個(gè)10秒鐘的Runnable A、消息進(jìn)隊(duì),MessageQueue調(diào)用nativePollOnce()阻塞,Looper阻塞;

緊接著post()一個(gè)Runnable B、消息進(jìn)隊(duì),判斷現(xiàn)在A時(shí)間還沒(méi)到、正在阻塞,把B插入消息隊(duì)列的頭部(A的前面),然后調(diào)用nativeWake()方法喚醒線程;

MessageQueue.next()方法被喚醒后,重新開(kāi)始讀取消息鏈表,第一個(gè)消息B無(wú)延時(shí),直接返回給Looper;

Looper處理完這個(gè)消息再次調(diào)用next()方法,MessageQueue繼續(xù)讀取消息鏈表,第二個(gè)消息A還沒(méi)到時(shí)間,計(jì)算一下剩余時(shí)間(假如還剩9秒)繼續(xù)調(diào)用nativePollOnce()阻塞;

直到阻塞時(shí)間到或者下一次有Message進(jìn)隊(duì);

這樣,基本上就能保證Handler.postDelayed()發(fā)布的消息能在相對(duì)精確的時(shí)間被傳遞給Looper進(jìn)行處理而又不會(huì)阻塞隊(duì)列了。

阻塞的。Looper.loop阻塞在MessageQueue的next方法中,有一個(gè)nativePollOnce的native方法,而在MessageQueue的enqueueMessage方法的最后nativeWake方法可以喚醒阻塞,使用了epoll機(jī)制

在next()方法內(nèi)部,如果有阻塞(沒(méi)有消息了或者只有Delay的消息),會(huì)把mBlocked這個(gè)變量標(biāo)記為true,在下一個(gè)Message進(jìn)隊(duì)時(shí)會(huì)判斷這個(gè)message的位置,如果在隊(duì)首并且時(shí)間滿足條件,會(huì)調(diào)用nativeWake()方法喚醒線程!

都是用sendMessageDelayed實(shí)現(xiàn),postDelay設(shè)置了delay數(shù)值,而post的delay數(shù)值為0,接著調(diào)用sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis)

一個(gè)線程只能又一個(gè)Looper,可以有多個(gè)Handler,不能互相發(fā)送消息,因?yàn)閐ispatchMessage中通過(guò)msg.target記錄了發(fā)送這個(gè)Message的Handler

直接使用HandlerThread

Looper.prepare();//Looper初始化

mHandler = new Handler(Looper.myLooper());

Looper.loop();//死循環(huán)

在主線程ActivityThread創(chuàng)建時(shí)進(jìn)行了主線程Looper的初始化,handler依賴于Looper,通過(guò)構(gòu)造函數(shù)建立聯(lián)系,而MessageQueue的實(shí)例在Looper中,新建的線程需要我們自己調(diào)用Looper.prepare();通過(guò)構(gòu)造函數(shù)傳入handler,然后用Looper.loop();開(kāi)啟消息機(jī)制。Android規(guī)定訪問(wèn)UI只能在主線程中進(jìn)行,否則拋出異常(UI控件不是線程安全的,加鎖使邏輯復(fù)雜,訪問(wèn)效率降低),通過(guò)ViewRootImpl對(duì)UI操作做了驗(yàn)證,由checkThread方法完成。

自己新建了Message并且把Runnable賦值給了Message的callback,在loop中會(huì)調(diào)用msg.target.dispatchMsg()以一定順序執(zhí)行第一順序就是Message中的callback

Q:IdleHandler 有什么用?

IdleHandler 是 Handler 提供的一種在消息隊(duì)列空閑時(shí),執(zhí)行任務(wù)的時(shí)機(jī);

當(dāng) MessageQueue 當(dāng)前沒(méi)有立即需要處理的消息時(shí),會(huì)執(zhí)行 IdleHandler;

Q:MessageQueue 提供了 add/remove IdleHandler 的方法,是否需要成對(duì)使用?

不是必須;

IdleHandler.queueIdle() 的返回值,可以移除加入 MessageQueue 的 IdleHandler;

Q:當(dāng) mIdleHanders 一直不為空時(shí),為什么不會(huì)進(jìn)入死循環(huán)?

只有在 pendingIdleHandlerCount 為 -1 時(shí),才會(huì)嘗試執(zhí)行 mIdleHander;

pendingIdlehanderCount 在 next() 中初始時(shí)為 -1,執(zhí)行一遍后被置為 0,所以不會(huì)重復(fù)執(zhí)行;

Q:是否可以將一些不重要的啟動(dòng)服務(wù),搬移到 IdleHandler 中去處理?

不建議;

IdleHandler 的處理時(shí)機(jī)不可控,如果 MessageQueue 一直有待處理的消息,那么 IdleHander 的執(zhí)行時(shí)機(jī)會(huì)很靠后;

Q:IdleHandler 的 queueIdle() 運(yùn)行在那個(gè)線程?

陷進(jìn)問(wèn)題,queueIdle() 運(yùn)行的線程,只和當(dāng)前 MessageQueue 的 Looper 所在的線程有關(guān);

子線程一樣可以構(gòu)造 Looper,并添加 IdleHandler;

Android——消息分發(fā)機(jī)制

什么是 Handler 機(jī)制 ?

Handler 機(jī)制是 Android 中用于 線程間通信 的一套通信機(jī)制。

為什么是 Handler ?Handler 機(jī)制為什么被那么多次的提及 ?

從Android4.0開(kāi)始,Android 中網(wǎng)絡(luò)請(qǐng)求強(qiáng)制不允許在主線程中操作,而更新UI的操作則不允許在子線程中執(zhí)行。當(dāng)在子線程中執(zhí)行網(wǎng)絡(luò)請(qǐng)求,拿到服務(wù)器返回的數(shù)據(jù)之后,要更新UI。由于系統(tǒng)的要求,勢(shì)必會(huì)產(chǎn)生一種矛盾:數(shù)據(jù)在子線程,更新UI要在主線程。此時(shí)我們必須要把數(shù)據(jù)返回到主線程中才行,Handler機(jī)制應(yīng)運(yùn)而生。

Android 中針對(duì)耗時(shí)的操作,放在主線程操作,輕者會(huì)造成 UI 卡頓,重則會(huì)直接無(wú)響應(yīng),造成 Force Close。同時(shí)在 Android 3.0 以后,禁止在主線程進(jìn)行網(wǎng)絡(luò)請(qǐng)求。

針對(duì)耗時(shí)或者網(wǎng)絡(luò)操作,那就不能在主線程進(jìn)行直接操作了,需要放在子線程或者是工作線程中進(jìn)行操作,操作完成以后,再更新主線程即 UI 線程。這里就涉及到一個(gè)問(wèn)題了,在子線程執(zhí)行完成以后,怎么能更新到主線程即 UI 線程呢,針對(duì)以上問(wèn)題,就需要用到 Android 的消息機(jī)制了,即: Handler, Message, MessageQueue, Looper 全家桶

Handler機(jī)制中最重要的四個(gè)對(duì)象

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

Looper :

Handler的使用:

MessageQueue:

Looper.loop()

Handler.dispatchMessage()

handler導(dǎo)致activity內(nèi)存泄露的原因:

handler發(fā)送的消息在當(dāng)前handler的消息隊(duì)列中,如果此時(shí)activity finish掉了,那么消息隊(duì)列的消息依舊會(huì)由handler進(jìn)行處理,若此時(shí)handler聲明為內(nèi)部類(非靜態(tài)內(nèi)部類),我們知道內(nèi)部類天然持有外部類的實(shí)例引用,這樣在GC垃圾回收機(jī)制進(jìn)行回收時(shí)發(fā)現(xiàn)這個(gè)Activity居然還有其他引用存在,因而就不會(huì)去回收這個(gè)Activity,進(jìn)而導(dǎo)致activity泄露。

假如在子線程執(zhí)行了耗時(shí)操作,這時(shí)用戶操作進(jìn)入了其他的 acitvity, 那么 MainActivity 就會(huì)被內(nèi)存回收的,但是這個(gè)時(shí)候發(fā)現(xiàn) Handler 還在引用著 MainActivity,內(nèi)存無(wú)法及時(shí)回收,造成內(nèi)存泄漏。

Handler 防止內(nèi)存泄漏常見(jiàn)方法:

為什么通過(guò) Handler 可以把子線程的結(jié)果通知或者攜帶給 UI 線程 ?

這里的 Handler 指的是主線程的 Handler ,同時(shí)與 Handler 配套的 Looper , MessageQueue 是在 UI 線程初始化的,所以在子線程中調(diào)用 Handler 發(fā)送消息可以更新 UI 線程。

Looper 在 UI 線程源碼, 在 ActivityThread 類:

android的事件處理機(jī)制有兩種

1.基于監(jiān)聽(tīng)的事件處理機(jī)制,有一個(gè)關(guān)鍵就是事件注冊(cè)。 但是我們?cè)趯?shí)踐的時(shí)候并沒(méi)有自己手動(dòng)的為某個(gè)視圖控件注冊(cè)監(jiān)聽(tīng)器。

解答: 我們會(huì)經(jīng)常用到 諸如 setOnclickListener(),OnTouchListener()方法等。 從字面意義理解,它為設(shè)置...監(jiān)聽(tīng)器。 但是,它 跟注冊(cè)還是頗有一些區(qū)別的。 我想注冊(cè)實(shí)踐監(jiān)聽(tīng)器,就是將它掛在在一個(gè)線程上,也就是說(shuō)有一個(gè)事件監(jiān)聽(tīng)線程,那么,有事件的視圖,就至少是雙線程的程序了。 不過(guò)很可惜,在去看set..Listener的源碼的時(shí)候,是看不到它在java源碼方面的具體實(shí)現(xiàn)的。 也就是說(shuō),要么它依賴操作系統(tǒng)實(shí)現(xiàn),要么它依賴jni實(shí)現(xiàn),并且,事件線程由jni管理。 換言之,實(shí)現(xiàn)注冊(cè)監(jiān)聽(tīng)是由ni實(shí)現(xiàn)的。

2.事件源的觸發(fā)流程:

解答: 學(xué)習(xí)過(guò)操作系統(tǒng)朋友應(yīng)該知道,操作系統(tǒng)的很多操作都是通過(guò)中斷來(lái)完成。 同理,比如一個(gè)點(diǎn)擊事件,android手機(jī)硬件中,包括了一個(gè)觸摸屏的硬件,它分為內(nèi)屏和外屏。 其中負(fù)責(zé)觸發(fā)屏幕點(diǎn)擊和觸摸中斷的為內(nèi)屏。 內(nèi)屏大概由五個(gè)層次構(gòu)成,具體有什么用不知道,反正我拆過(guò)~~~ 從內(nèi)屏上,當(dāng)有電容屏感應(yīng)的時(shí)候,會(huì)接收到你觸摸的位置信息,甚至觸摸力度?。?! 這個(gè)消息經(jīng)由系統(tǒng)中斷(具有最高優(yōu)先級(jí),應(yīng)該是由最高優(yōu)先級(jí)的進(jìn)程通知)發(fā)送給cpu,經(jīng)由cpu通過(guò)進(jìn)程間的消息機(jī)制傳遞給這個(gè)進(jìn)程(當(dāng)前正在用戶界面運(yùn)行的進(jìn)程,這時(shí)候只有一個(gè)),也就是這個(gè)程序運(yùn)行的內(nèi)存空間的某個(gè)點(diǎn)。(或者說(shuō)通過(guò)廣播機(jī)制,將這個(gè)事件發(fā)送給所有的app也是有可能的)。

Android權(quán)限機(jī)制

我們知道 Android 應(yīng)用程序是沙箱隔離的,每個(gè)應(yīng)用都有一個(gè)只有自己具有讀寫權(quán)限的專用數(shù)據(jù)目錄。但是如果應(yīng)用要訪問(wèn)別人的組件或者一些設(shè)備上全局可訪問(wèn)的資源,這時(shí)候權(quán)限機(jī)制就能系統(tǒng)化地規(guī)范并強(qiáng)制各類應(yīng)用程序的行為準(zhǔn)則。

Android 安全性概覽

在 Android 中,一個(gè)權(quán)限,本質(zhì)上是一個(gè)字符串,一個(gè)可以表示執(zhí)行特定操作的能力的字符串。比如說(shuō):訪問(wèn) SD 卡的能力,訪問(wèn)通訊錄的能力,啟動(dòng)或訪問(wèn)一個(gè)第三方應(yīng)用中的組件的能力。 權(quán)限被授予了之后,首先會(huì)在內(nèi)存和本地中有記錄,這在調(diào)用系統(tǒng)binder服務(wù)和其他應(yīng)用組件時(shí)做鑒權(quán)依據(jù),比如調(diào)用系統(tǒng)binder服務(wù)時(shí)會(huì)通過(guò)Binder.getCallingUid()拿到調(diào)用者的Uid,而Uid一般都是與應(yīng)用包名一一對(duì)應(yīng)的,再拿這個(gè)Uid到PMS里去查這個(gè)應(yīng)用對(duì)應(yīng)的權(quán)限。 其次會(huì)按被授予的權(quán)限將應(yīng)用分到某個(gè)組。 可以參考

自定義權(quán)限的應(yīng)用場(chǎng)景在于限制其它應(yīng)用對(duì)本應(yīng)用四大組件的訪問(wèn)。具體用法可以參考

pm list permissions -f 命令可以詳細(xì)查看 Android 所有預(yù)定義的權(quán)限。

更詳細(xì)的權(quán)限信息參考

可以看到一個(gè)權(quán)限的信息包括:定義的包名、標(biāo)簽、描述、 權(quán)限組 和 保護(hù)級(jí)別 。

權(quán)限根據(jù)設(shè)備的功能或特性分為多個(gè)組。如果應(yīng)用已在相同權(quán)限組中被授予另一危險(xiǎn)權(quán)限,系統(tǒng)將立即授予該權(quán)限,如READ_CONTACTS和WRITE_CONTACTS。

SYSTEM_ALERT_WINDOW 和 WRITE_SETTINGS 由于其特殊性,其申請(qǐng)方式與其它權(quán)限都不同。

其授予流程如下:

(關(guān)于 AppOpsManager 是什么可以參考: )

這里簡(jiǎn)要分析下ActivityCompat#requestPermissions的流程:

更詳細(xì)的權(quán)限授予流程源碼分析可以參考:

普通權(quán)限: 清單文件中聲明即可。

危險(xiǎn)權(quán)限: 方式一: pm grant application_package android.permission.CHANGE_CONFIGURATION 方式二:appops set application_package permission_num 0/1

appops可以授予的權(quán)限參考 android.app.AppOpsManager 中的聲明

系統(tǒng)簽名權(quán)限: 方式一:將app遷移到system/priv-app目錄中。 方式二:看不懂,參考

android 4.4 訪問(wèn)sd卡需要申請(qǐng)權(quán)限。 您的應(yīng)用在 Android 4.4 上運(yùn)行時(shí)無(wú)法讀取外部存儲(chǔ)空間上的共享文件,除非您的應(yīng)用具有 READ_EXTERNAL_STORAGE 權(quán)限。也就是說(shuō),沒(méi)有此權(quán)限,您無(wú)法再訪問(wèn) getExternalStoragePublicDirectory() 返回的目錄中的文件。但是,如果您僅需要訪問(wèn) getExternalFilesDir() 提供的您的應(yīng)用特有目錄,那么,您不需要 READ_EXTERNAL_STORAGE `權(quán)限。

android 6.0 運(yùn)行時(shí)權(quán)限。 此版本引入了一種新的權(quán)限模式,如今,用戶可直接在運(yùn)行時(shí)管理應(yīng)用權(quán)限。這種模式讓用戶能夠更好地了解和控制權(quán)限,同時(shí)為應(yīng)用開(kāi)發(fā)者精簡(jiǎn)了安裝和自動(dòng)更新過(guò)程。用戶可為所安裝的各個(gè)應(yīng)用分別授予或撤銷權(quán)限。 對(duì)于以 Android 6.0(API 級(jí)別 23)或更高版本為目標(biāo)平臺(tái)的應(yīng)用,請(qǐng)務(wù)必在運(yùn)行時(shí)檢查和請(qǐng)求權(quán)限。要確定您的應(yīng)用是否已被授予權(quán)限,請(qǐng)調(diào)用新增的 checkSelfPermission() 方法。要請(qǐng)求權(quán)限,請(qǐng)調(diào)用新增的 requestPermissions() 方法。即使您的應(yīng)用并不以 Android 6.0(API 級(jí)別 23)為目標(biāo)平臺(tái),您也應(yīng)該在新權(quán)限模式下測(cè)試您的應(yīng)用。 如需了解有關(guān)在您的應(yīng)用中支持新權(quán)限模式的詳情,請(qǐng)參閱 使用系統(tǒng)權(quán)限 。如需了解有關(guān)如何評(píng)估新模式對(duì)應(yīng)用的影響的提示,請(qǐng)參閱 權(quán)限最佳做法 。

android 7.+ 應(yīng)用間共享文件要使用FileProvider。 對(duì)于面向 Android 7.0 的應(yīng)用,Android 框架執(zhí)行的 StrictMode API 政策禁止在您的應(yīng)用外部公開(kāi) 。如果一項(xiàng)包含文件 URI 的 intent 離開(kāi)您的應(yīng)用,則應(yīng)用出現(xiàn)故障,并出現(xiàn) FileUriExposedException 異常。 要在應(yīng)用間共享文件,您應(yīng)發(fā)送一項(xiàng) content:// URI,并授予 URI 臨時(shí)訪問(wèn)權(quán)限。進(jìn)行此授權(quán)的最簡(jiǎn)單方式是使用 FileProvider `類。如需了解有關(guān)權(quán)限和共享文件的詳細(xì)信息,請(qǐng)參閱 共享文件 。

android 8.+

同一權(quán)限組的權(quán)限在被授予了之后也需要顯式的再申請(qǐng)一次。

在 Android 8.0 之前,如果應(yīng)用在運(yùn)行時(shí)請(qǐng)求權(quán)限并且被授予該權(quán)限,系統(tǒng)會(huì)錯(cuò)誤地將屬于同一權(quán)限組并且在清單中注冊(cè)的其他權(quán)限也一起授予應(yīng)用。 對(duì)于針對(duì) Android 8.0 的應(yīng)用,此行為已被糾正。系統(tǒng)只會(huì)授予應(yīng)用明確請(qǐng)求的權(quán)限。然而,一旦用戶為應(yīng)用授予某個(gè)權(quán)限,則所有后續(xù)對(duì)該權(quán)限組中權(quán)限的請(qǐng)求都將被自動(dòng)批準(zhǔn)。 例如,假設(shè)某個(gè)應(yīng)用在其清單中列出 READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE 。應(yīng)用請(qǐng)求 READ_EXTERNAL_STORAGE ,并且用戶授予了該權(quán)限。如果該應(yīng)用針對(duì)的是 API 級(jí)別 24 或更低級(jí)別,系統(tǒng)還會(huì)同時(shí)授予 WRITE_EXTERNAL_STORAGE ,因?yàn)樵摍?quán)限也屬于同一 STORAGE 權(quán)限組并且也在清單中注冊(cè)過(guò)。如果該應(yīng)用針對(duì)的是 Android 8.0,則系統(tǒng)此時(shí)僅會(huì)授予 READ_EXTERNAL_STORAGE ;不過(guò),如果該應(yīng)用后來(lái)又請(qǐng)求 WRITE_EXTERNAL_STORAGE ,則系統(tǒng)會(huì)立即授予該權(quán)限,而不會(huì)提示用戶。

android 9

隱私權(quán)限變更。

為了增強(qiáng)用戶隱私,Android 9 引入了若干行為變更,如限制后臺(tái)應(yīng)用訪問(wèn)設(shè)備傳感器、限制通過(guò) Wi-Fi 掃描檢索到的信息,以及與通話、手機(jī)狀態(tài)和 Wi-Fi 掃描相關(guān)的新權(quán)限規(guī)則和權(quán)限組。

android 10

隱私權(quán)變更。

外部存儲(chǔ)訪問(wèn)權(quán)限范圍限定為應(yīng)用文件和媒體,在后臺(tái)運(yùn)行時(shí)訪問(wèn)設(shè)備位置信息需要權(quán)限,針對(duì)從后臺(tái)啟動(dòng) Activity 的限制等。

android 11

隱私權(quán)限變更。

更詳細(xì)的版本變更請(qǐng)參考

Android 系統(tǒng)運(yùn)行機(jī)制 【Looper】【Choreographer】篇

目錄:

1 MessageQueue next()

2 Vsync

3 Choreographer doFrame

4 input

系統(tǒng)是一個(gè)無(wú)限循環(huán)的模型, Android也不例外,進(jìn)程被創(chuàng)建后就陷入了無(wú)限循環(huán)的狀態(tài)

系統(tǒng)運(yùn)行最重要的兩個(gè)概念:輸入,輸出。

Android 中輸入 輸出 的往復(fù)循環(huán)都是在 looper 中消息機(jī)制驅(qū)動(dòng)下完成的

looper 的循環(huán)中, messageQueue next 取消息進(jìn)行處理, 處理輸入事件, 進(jìn)行輸出, 完成和用戶交互

應(yīng)用生命周期內(nèi)會(huì)不斷 產(chǎn)生 message 到 messageQueue 中, 有: java層 也有 native層

其中最核心的方法就是 messageQueue 的 next 方法, 其中會(huì)先處理 java 層消息, 當(dāng) java 層沒(méi)有消息時(shí)候, 會(huì)執(zhí)行 nativePollOnce 來(lái)處理 native 的消息 以及監(jiān)聽(tīng) fd 各種事件

從硬件來(lái)看, 屏幕不會(huì)一直刷新, 屏幕的刷新只需要符合人眼的視覺(jué)停留機(jī)制

24Hz , 連續(xù)刷新每一幀, 人眼就會(huì)認(rèn)為畫面是流暢的

所以我們只需要配合上這個(gè)頻率, 在需要更新 UI 的時(shí)候執(zhí)行繪制操作

如何以這個(gè)頻率進(jìn)行繪制每一幀: Android 的方案是 Vsync 信號(hào)驅(qū)動(dòng)。

Vsync 信號(hào)的頻率就是 24Hz , 也就是每隔 16.6667 ms 發(fā)送一次 Vsync 信號(hào)提示系統(tǒng)合成一幀。

監(jiān)聽(tīng)屏幕刷新來(lái)發(fā)送 Vsync 信號(hào)的能力,應(yīng)用層 是做不到的, 系統(tǒng)是通過(guò) jni 回調(diào)到 Choreographer 中的 Vsync 監(jiān)聽(tīng), 將這個(gè)重要信號(hào)從 native 傳遞到 java 層。

總體來(lái)說(shuō) 輸入事件獲取 Vsync信號(hào)獲取 都是先由 native 捕獲事件 然后 jni 到 java 層實(shí)現(xiàn)業(yè)務(wù)邏輯

執(zhí)行的是 messageQueue 中的關(guān)鍵方法: next

next 主要的邏輯分為: java 部分 和 native 部分

java 上主要是取java層的 messageQueue msg 執(zhí)行, 無(wú) msg 就 idleHandler

java層 無(wú) msg 會(huì)執(zhí)行 native 的 pollOnce@Looper

native looper 中 fd 監(jiān)聽(tīng)封裝為 requestQueue, epoll_wait 將 fd 中的事件和對(duì)應(yīng) request 封裝為 response 處理, 處理的時(shí)候會(huì)調(diào)用 fd 對(duì)應(yīng)的 callback 的 handleEvent

native 層 pollOnce 主要做的事情是:

vsync 信號(hào),輸入事件, 都是通過(guò)這樣的機(jī)制完成的。

epoll_wait 機(jī)制 拿到的 event , 都在 response pollOnce pollInner 處理了

這里的 dispatchVsync 從 native 回到 java 層

native:

java:

收到 Vsync 信號(hào)后, Choreographer 執(zhí)行 doFrame

應(yīng)用層重要的工作幾乎都在 doFrame 中

首先看下 doFrame 執(zhí)行了什么:

UI 線程的核心工作就在這幾個(gè)方法中:

上述執(zhí)行 callback 的過(guò)程就對(duì)應(yīng)了圖片中 依次處理 input animation traversal 這幾個(gè)關(guān)鍵過(guò)程

執(zhí)行的周期是 16.6ms, 實(shí)際可能因?yàn)橐恍?delay 造成一些延遲、丟幀

input 事件的整體邏輯和 vsync 類似

native handleEvent ,在 NativeInputEventReceiver 中處理事件, 區(qū)分不同事件會(huì)通過(guò) JNI

走到 java 層,WindowInputEventReceiver 然后進(jìn)行分發(fā)消費(fèi)

native :

java:

input事件的處理流程:

輸入event deliverInputEvent

deliver的 input 事件會(huì)來(lái)到 InputStage

InputStage 是一個(gè)責(zé)任鏈, 會(huì)分發(fā)消費(fèi)這些 InputEvent

下面以滑動(dòng)一下 recyclerView 為例子, 整體邏輯如下:

vsync 信號(hào)到來(lái), 執(zhí)行 doFrame,執(zhí)行到 input 階段

touchEvent 消費(fèi), recyclerView layout 一些 ViewHolder

scroll 中 fill 結(jié)束,會(huì)執(zhí)行 一個(gè) recyclerView viewProperty 變化, 觸發(fā)了invalidate

invalidate 會(huì)走硬件加速, 一直到達(dá) ViewRootImpl , 從而將 Traversal 的 callback post choreographer執(zhí)行到 traversal 階段就會(huì)執(zhí)行

ViewRootImpl 執(zhí)行 performTraversal , 會(huì)根據(jù)目前是否需要重新layout , 然后執(zhí)行l(wèi)ayout, draw 等流程

整個(gè) input 到 traversal 結(jié)束,硬件繪制后, sync 任務(wù)到 GPU , 然后合成一幀。

交給 SurfaceFlinger 來(lái)顯示。

SurfaceFlinger 是系統(tǒng)進(jìn)程, 每一個(gè)應(yīng)用進(jìn)程是一個(gè) client 端, 通過(guò) IPC 機(jī)制,client 將圖像顯示工作交給 SurfaceFlinger

launch 一個(gè) app:


當(dāng)前題目:android機(jī)制,安卓的機(jī)制
文章位置:http://weahome.cn/article/hospgh.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部