王紅元高級講師
專注移動開發(fā)領(lǐng)域,多年iOS開發(fā)和教學經(jīng)驗,曾經(jīng)帶領(lǐng)團隊開發(fā)出眾多款 優(yōu)秀APP作品。
國內(nèi)知名視頻聊天軟件 < 新浪秀場 > 就出自王老師之手,王老師全 面負責 < 新浪秀場 > iOS客戶端的設(shè)計和開發(fā),并參與了 < 新浪秀場 > Android、Windows 、web端
開發(fā)。同時王老師還曾兼職擔任過多家公司技術(shù)顧問,幫助其解決開發(fā)中的 重點難題。
除此之外,王老師還主導(dǎo)開發(fā)了< 智慧城市 > < 天翼看交通 > < 公交wifi > 等熱門APP。王老師開發(fā)過的作品涉及旅游、交通、社交、視頻等方面,對即時聊天、流媒體等技術(shù)有深入研究。
王老師不但開發(fā)經(jīng)驗豐富,授課風趣幽默,且激情四射。擅長以各種生活中 的案例出發(fā),幫助學生理解消化學習中的各種難點。另外,王老師教學總是以學生角度思考講解,備受學生喜愛。
現(xiàn)在學習Java還有前途嗎?
在互聯(lián)網(wǎng)行業(yè),Java工程師是一個技術(shù)含量非常高的崗位,支撐了互聯(lián)網(wǎng)行 業(yè)的半壁江山,全世界有一千萬Java程序員,目前還在有更多的計算機愛好者向Java的大門奔來。Java發(fā)展了20多年,關(guān)于Java的悲觀論調(diào)也不時出現(xiàn) ,現(xiàn)在學Java還有前途嗎?是否已經(jīng)過了紅利期了呢?
Java作為所有編程語言中熱門技術(shù),可以說它無處不在,目前全球有著數(shù)十 億的設(shè)備正在運行著Java,很多服務(wù)器程序都是用Java編寫,用以處理每天超過數(shù)以千萬的數(shù)據(jù)。
無論是手機軟件、手機Java游戲還是電腦軟件,每一次購物到每一筆支付成 功,都離不開Java,越來越多的企業(yè)也正采用Java語言開發(fā)網(wǎng)站,而在所有程序員中,Java開發(fā)工程師就占據(jù)了20%的比例。
從國內(nèi)排名靠前網(wǎng)站的主要開發(fā)語言,也可以看出Java在各大開發(fā)語言中的 地位。淘寶、搜狐、網(wǎng)易等一線互聯(lián)網(wǎng)公司,都在使用Java開發(fā)語言。
這也不難理解,為什么Java現(xiàn)在這么火爆,吸引越來越多的人學習,根本原 因,還是因為企業(yè)對Java的認可和應(yīng)用。
Java有沒有前途,需要我們認清自己今后應(yīng)該怎么走自己的路線,是走技術(shù) ,還是走管理。走技術(shù)路線:從初級、中級、高級再到軟件架構(gòu)師。如果說走管理路線:項目經(jīng)理、部門經(jīng)理、技術(shù)總監(jiān)。只有清楚了自己要走的路線 后,再往決定的那一方面去努力,學習。除此以外,還有一些人學了這一專業(yè)后,從事銷售顧問、培訓(xùn)講師、自己創(chuàng)業(yè)的都有,關(guān)鍵是自己要認識自己 ,自己更適何哪一條路。
所以,先認清“正確的結(jié)果”,根據(jù)正確的結(jié)果去設(shè)計你的過程。當一個人 具有明確的職業(yè)目標時,就會對有助于實現(xiàn)目標的蛛絲馬跡都特別敏感,做事情相應(yīng)也就會很有目的性,而不是稀里糊涂的。所以,就容易到達自己的 目的。如果沒有職業(yè)目標,腳踩西瓜皮滑到哪里是哪里,學什么技術(shù)都沒前途。
在未來的幾年,Java工程師人才的需求還在不斷的加大,由于人才的緊缺, 這個崗位相對于其它專業(yè)薪資待遇還是不錯的,而且Java工程師的待遇是與工作經(jīng)驗直接掛勾的,當你有了豐富的經(jīng)驗以后,你在這個行業(yè)里就比較搶 手了,而且企業(yè)所出的薪酬也是相當高的,到時只有你選擇他們了。
大數(shù)據(jù)核心知識
大數(shù)據(jù)核心知識
Hadoop基礎(chǔ)
Hadoop1介紹
hadoop1架構(gòu)
hadoop2架構(gòu)(對比hadoop1)
hadoop2環(huán)境搭建
HDFS操作
yarn操作
Hadoop應(yīng)用
Hive數(shù)據(jù)倉庫
zookeeper系統(tǒng)服務(wù)
HBase非關(guān)系型數(shù)據(jù)庫
Sqoop數(shù)據(jù)庫抽取工具
Flume日志抽取工具
Spark基礎(chǔ)
環(huán)境搭建
Spark平臺介紹
RDD彈性分布式數(shù)據(jù)集
Scala編程
Spark應(yīng)用
Spark-SQL組件
DataFrame組件
課程優(yōu)勢
1.真實的企業(yè)項目;
2.目前企業(yè)中應(yīng)用廣泛的技術(shù)路線;
3.部分Spark源碼剖析,從源碼層面提升問題解決能力。
4.從hadoop1到hadoop2機制原理詳細解說;
5.生產(chǎn)環(huán)境hadoop集群調(diào)優(yōu)經(jīng)驗;
6.企業(yè)真實項目實戰(zhàn);
本階段學習目標
1.了解hadoop機制原理 ;
2.了解hadoop集群搭建過程;
3.了解Hdfs API使用以及mr編程模型;
4.了解hive、hbase、sqoop、flume等組件的使用方法;
5.Spark平臺的優(yōu)勢以及Spark集群的搭建過程;
6.Scala程序設(shè)計基礎(chǔ);
7.Spark-SQL和DataFrame API詳解。
本階段學習效果
1.了解hadoop集群的搭建過程;
2.能夠**mr和hive來實現(xiàn)簡單的數(shù)據(jù)清洗的業(yè)務(wù)需求;
3.能夠了解數(shù)據(jù)的抽取,轉(zhuǎn)換,清洗,建模,入庫過程;
4.掌握Spark集群的搭建;
5.掌握函數(shù)式編程思想,能夠根據(jù)業(yè)務(wù)需求編寫高質(zhì)量的Scala程序;
6.掌握大規(guī)模離線數(shù)據(jù)的計算、分析能力。
SystemUI架構(gòu)分析
>
SystemUI架構(gòu)分析
SystemUI架構(gòu)分析 前言 1SystemUI介紹 1SystemUI摘要 2什么是SystemUI 2SystemUI的啟動過程 3SystemUI的SERVICES 1音量控制 11音量控制簡介 12音量控制SERVICE的初始化 13控制音量過程 2RingtonePlayer 3電源管理 4任務(wù)管理 5存儲通知 6鎖屏 7通知欄 4總結(jié)
前言
本文描述Android系統(tǒng)中一個核心應(yīng)用SystemUI,詳細贅述SystemUI中幾大模塊功能的實現(xiàn)過程。由于作者水平有限,如發(fā)現(xiàn)本文中錯誤的地方,歡迎指正。
1、SystemUI介紹
1.1、SystemUI摘要
在Android系統(tǒng)中SystemUI是以應(yīng)用的形式運行在Android系統(tǒng)當中,即編譯SystemUI模塊會生產(chǎn)APK文件,源代碼路徑在frameworks/base/packages/SystemUI/,安裝路徑system/PRiv-app/-SystemUI。
1.2、什么是SystemUI
在前文1.1章節(jié)中可知,SystemUI是一個普通的APK文件,即是一個普通的APP,但是,手機使用者看見的所有SystemUI的內(nèi)容都不像是一個APP,為什么?既然是一個應(yīng)用,就是完成特定的功能,SystemUI主要完成的功能有: (1)、Status bars (2)、Navigation bars (3)、Notification (4)、Lockscreen (5)、Quick settings (6)、Overview(recent task switcher) (7)VolumeUI
2、SystemUI的啟動過程
正如1.2中所述,SystemUI任何內(nèi)容都不像一個APP,自然它的啟動也不像大多APP一樣啟動一個Activity。SystemUI顧名思義就是全局UI,必須在開機過程中完成啟動,并不可退出。 回顧Android系統(tǒng)開機的過程,會創(chuàng)建server進程維護系統(tǒng)各種服務(wù),當服務(wù)啟動完成后調(diào)用systemReady方法(如果讀者不了解這個過程自行學習Android Boot Flow),如下圖:
繼續(xù)跟蹤startSystemUi()方法的實現(xiàn)如下圖:
上圖中可以看到**熟悉的startServiceAsUser()方法啟動SystemUI中的SystemUIService。由APP的啟動過程可知(如果讀者不了解這個過程可自行學習),Android系統(tǒng)會給應(yīng)用創(chuàng)建獨立的進程,并實例化application對象,在SystemUI源碼中的AndroidManifest.xml文件可以看到下圖的配置:
上圖中在application標簽中指定了SystemUIApplication對象,因此在啟動SystemUI應(yīng)用時會創(chuàng)建SystemUIApplication對象并回調(diào)onCreate()方法,如下圖:
onCreate()中注冊ACTION_BOOT_COMPLETED廣播,并調(diào)用mServices.onBootCompleted()方法,將在后面的內(nèi)容中贅述該方法。應(yīng)用成功啟動后便可執(zhí)行上文中提到的SystemUIService服務(wù),并回調(diào)onCreate()方法,如下圖:
上圖中**獲取應(yīng)用的Application實例SystemUIApplication對象,調(diào)用startServiceIfNeeded(),如下圖:
上圖中讀者可能會問:mService的實質(zhì)是什么?回顧1.2章節(jié)中的內(nèi)容,SystemUI主要分幾大模塊,即在SystemUI中每個模塊是一個Service,這樣一來,各個模塊就非常獨立。上圖中用java映射機制把每個Service的對象實例化,并調(diào)用start()方法啟動各個服務(wù),start()方法的具體實現(xiàn)在分析各個服務(wù)時再贅述。先了解mService實質(zhì)都包含哪些具體“對象”,如下圖:
如上圖所示,SystemUI需要啟動的Service包括KeyguardViewMediator、Recent、VolumeUI、SystemBars、StorageNotification、PowerUI、RingtongPlayer共7個,每個service的具體實現(xiàn)和功能將在下文中描述。在圖6中可以看到,實例化每個對象是向上轉(zhuǎn)型為SystemUI對象,即圖7中的所有service統(tǒng)一繼承了SystemUI類,如下圖:
SystemUI類提供start()、onConfigurationChanged()、dump()等重要方法,每個方法在各個service中實現(xiàn)不一樣,下面將一一描述每個service在SystemUI類中的方法的實現(xiàn)。 至此,SystemUI的啟動基本完成,從上文可知,SystemUI是系統(tǒng)中非常核心的應(yīng)用,在Android系統(tǒng)開機過程中Server進程直接發(fā)起SystemUI啟動,SystemUI也是固化程序,在保證系統(tǒng)正常運行發(fā)揮了非常重要的作用。
3、SystemUI的SERVICES
3.1、音量控制
3.1.1、音量控制簡介
如圖章節(jié)1.2中的VolumeUI所示,當用戶操作音量鍵時,會彈出相應(yīng)的UI顯示,并可以設(shè)置音量大小和情景模式。VolumeUI的主要代碼在SystemUI/volume下。在不同模式下,音量鍵觸發(fā)的UI顯示樣式不一樣,分別是通話、鈴聲(通知)、音樂、鬧鈴、藍牙輸出等,如下圖 9-13
3.1.2、音量控制SERVICE的初始化
在第二章節(jié)中SystemUI的啟動過程提到,SystemUI的所有Service**SystemUI類的start()方法啟動,并且**圖7可以知道,volume service的VolumeUI繼承了SystemUI類,所以start()實質(zhì)是執(zhí)行VolumeUI中的方法,如下圖:
如上圖中的代碼,首先讀取VolumeUI的開關(guān),如果mEnabled為true,則調(diào)用initPanel()方法實例化UI等控件元素(如圖15),實例化VolumeController控制器(如圖17),調(diào)用putComponent()保存對象實例,調(diào)用updateController()設(shè)置控制器(如圖18)。
上圖中主要是new一個VolumePanel對象,VolumePanel是Handler的子類,且又是VolumeUI的Pannel,因此,VolumePanel負責繪制VolumeUI的內(nèi)容和控制VolumeUI的顯示。先看看VolumeUI的創(chuàng)建過程:
從上圖中的代碼可見,VolumeUI是以Dialog的形式顯示UI,VolumePanel的實例化過程創(chuàng)建Dialog實例和初始化ZenModePanel,到此VolumePanel將會待命。上文中提到VolumePanel同時是Handler的子類,一旦VolumePanel收到相關(guān)的Message時,將會處理UI的顯示和關(guān)閉。
上圖是VolumeController的實現(xiàn)代碼,主要實現(xiàn)對VolumeUI的Panel的控制,例如上圖中的volumeChanged()控制Panel的顯示和變化,dismissNow()控制Panel的關(guān)閉。那么VolumeController是被誰管控呢?如下圖:
圖中可以看到先**設(shè)置Provider讀取是否允許systemui控制volume,如果允許,則設(shè)置**AudioManager的實例設(shè)置VolumeController到AudioService(讀者如果不了解這個過程,可以自行閱讀Android Audio策略)。至此,VolumeUI的初始化全部完成。 **本節(jié)的學習,VolumeUI的架構(gòu)如下圖:
3.1.3、控制音量過程
當SystemUI的VolumeUI當前不是活動窗口時,一般情況下,音量的設(shè)置是**音量鍵進行操作,當用戶操作音量鍵時,如果用戶不攔截音量鍵事件,那么默認音量鍵的事件將會在Window中被消化,Window將捕獲到的音量鍵事件**Binder機制將音量變化信息傳送到MediasessionService,MediaSessionService同樣**Binder機制接著傳送到AudioService,**后AudioService也同樣**Binder機制把信息傳送給SystemUI(VolumeUI),VolumeUI將會作出相應(yīng)的變化。下面將詳細了解這個過程: 當手機設(shè)備當前活動窗口在Laucher桌面,Laucher沒有對音量鍵事件作攔截操作,音量鍵事件將會在PhoneWindow中被消化。在Android的單次點擊事件中,分down和up兩種事件,分別被分發(fā)到PhoneWindow的onKeyUp()和onKeyDown()方法中,如下圖20-21:
圖20是消化down事件,圖21是消化up事件,但音量鍵還有上音量鍵( )和下音量鍵(-),從這兩張圖可以看到,KEYCODE_VOLUME_UP沒有作任何處理,上音量鍵( )的事件會在下音量鍵中消化(-), 在down和up事件中都是調(diào)用sendAdjustVolumeBy()同一個方法,傳遞三個參數(shù),**個參數(shù)是指定音量類型,mVolumeControlStream為默認值,取值Integer.MIN_VALUE,圖20和圖21相同,第二個是delta,音量控制類型,即增加或減少,圖20傳遞direction,圖21傳遞0,direction取值1或-1,即1:增加、0:不變、-1:減少,第三個參數(shù)是flags,控制VolumeUI顯示,每個參數(shù)具體的控制的實現(xiàn)代碼將在下文中描述。繼續(xù)跟蹤流程,Laucher進程**Binder機制把信息傳送到MediaSessionService,如下圖:
上圖中有獲取MediaSessionRecord的對象來控制音量,這里的session變量的值是null,如果讀者對此感興趣可自行閱讀相關(guān)資料。繼續(xù)看dispatchAjustVolumeLocked()方法:
圖23中可以知道參數(shù)只是多了一個packageName,其它的都是圖20或圖21中的參數(shù)值。接著往下看:
在圖20或圖21中有描述suggestedStreamType的值是Integer.MIN_VALUE,在上圖中**getActiveStreamType()方法對值進行轉(zhuǎn)換,變成streamType,它的取值可能是0到10,分別控制不同類型的音量,如3.1.1章節(jié)中所以,本例子streamType的值是2,即調(diào)整的是鈴聲(通知)的音量。接著又調(diào)用了adjustStreamVolume()方法,如下:
adjustStreamVolume()方法對direction和streamType的合法進行校驗,direction取值-1到1,streamType取值0到10。之后**mStreamState獲取oldIndex、newIndex和index值,其中oldindex和index作為sendVolumeUpdate()方法的參數(shù),將會影響音量變化的廣播和AudioProfile,關(guān)于AudioProfile讀者感興趣可以自行學習。圖中還可以看到這里還設(shè)置了HDMI接口輸出。繼續(xù)看sendVolumeUpdate()方法:
在sendVolumeUpdate()方法中處理了幾個事件,一個postVolumeChanged()方法,**終通知SystemUI,后面贅述。接著發(fā)送注冊到AudioManager.VOLUME_CHANGED_ACTION的action的廣播,通知音量改變并攜帶音量大小的原值oldIndex和新值index,**后通知AudioProfile。繼續(xù)看postVolumeChanged()方法:
這里**mControlle對象調(diào)用volumeChanged(),mController實質(zhì)是一個什么類的實例,回顧3.1.2章節(jié)中的圖18,updateController()方法設(shè)置了VolumeController的實例,因此mController正是VolumeController在AudioService中的句柄,**Binder機制,把音量變化的信息從AudioService傳輸?shù)絊ystemUI進程。轉(zhuǎn)移到SystemUI,如下圖:
從AudioService回調(diào)到volumeChanged()方法,接著調(diào)用mPanel的postVolumeChanged()方法,mPanel在前文3.1.2章節(jié)的圖15中有描述,是VolumePanel的實例,前文中提到,VolumePanel是Handler的子類,也是VolumeUI的Panel,下面結(jié)合代碼分析VolumePanel的具體功能:
上文提到VolumePanel是Handler的子類,圖29中VolumePanel將發(fā)送MSG_VOLUME_CHANGED的Message到自身持有的線程,接著看MSG_VOLUME_CHANGED的代碼:
上圖中直接又調(diào)用了onShowVolumeChanged()方法,顧名思義是顯示音量變化的UI,后面接著繼續(xù)調(diào)用resetTimeout()方法,先跟蹤onShowVolumeChanged()方法:
上圖中首先調(diào)用getStreamVolume()方法獲取對應(yīng)streamType當前的音量值,**StreamControl匹配streamType的UI,StreamControl是一個容器,在VolumeUI的初始化時被實例化,裝載不同streamType的UI配置,并保存到mStreamControls數(shù)組對象中,因此streamType的值確定了StreamControl的類型,StreamControl確定了Dialog顯示的UI類型。確定StreamControl的類型后,調(diào)用updateSliderProgress()方法更新界面控件,**后調(diào)用mDialog.show()方法繪制界面。至此,從按下音量鍵到調(diào)用mDialog.show(),設(shè)備對點擊事件作出相應(yīng),并顯示相應(yīng)的UI到界面上。 回顧圖31,resetTimeout()方法的實現(xiàn)如下:
這里會延時發(fā)送一個空消息到VolumePanel,what為MSG_TIMEOUT,mTimeoutDelay的值為3000,跟蹤MSG_TIMEOUT的處理過程:
很簡單,實現(xiàn)的功能就是在VolumeUI顯示后,延時3秒自動把VolumeUI關(guān)閉。 到此SystemUI的VolumeUI service分析完畢,VolumeUI的流程簡單清晰,代碼簡潔,閱讀方便?;仡橵olumeUI整個控制流程,可用下圖總結(jié):
上圖中PhoneWindow是當前活動窗口的進程的PhoneWindow實例捕獲音量鍵事件,當前活動窗口的可以**自身的PhoneWindow對象實例設(shè)置streamType,即控制音量鍵事件觸發(fā)的VolumeUI類型。當應(yīng)用程序攔截音量鍵事件,那么PhoneWindow將無法捕獲到音量鍵事件,此時音量鍵事件將不遵行上圖的流程。如果當前活動窗口時SystemUI,則直接由SystemUI所在進程的活動窗口的PhoneWindow對象實例獲取到音量鍵事件,這時音量鍵事件的轉(zhuǎn)發(fā)和處理和在其它進程(如Laucher)中略有不同,讀者感興趣可以自行比較,本文不再論述。
3.2、RingtonePlayer
RingtonePlayer在SystemUI中扮演播放者的角色,代碼在SystemUI/media/目錄下,RingtonePlayer的代碼很少,功能很簡單,同VolumeUI,RingtonePlayer繼承SystemUI類,SystemUI應(yīng)用啟動時調(diào)用start()方法:
Start()方法很簡潔,**AudioService的句柄mAudioService的setRingtonePlayer()方法設(shè)置mCallback,mCallback實質(zhì)是IRingtonePlayer對象的實例,如下圖:
IRingtonePlayer有play()、stop()等方法,分別是播放音樂和停止音樂。關(guān)于RingtonePlayer的作用,讀者可以參考下圖:
SystemUI啟動后**Binder機制把IRingtonePlayer的句柄設(shè)置到AudioServie,其它應(yīng)用便可**AudioService獲取IRingtonePlayer的句柄,在**Binder機制操作RingtonePlayerService去播放聲音文件。如果讀者感興趣可自行深入學習Ringtone策略和架構(gòu)。
3.3、電源管理
電源管理即PowerUI,負責監(jiān)控電源的變化和通知,源碼路徑在SystemUI/power。同樣PowerUI繼承SystemUI類,start()方法如下:
上圖可以知道,start()方法注冊鑒定Setting.Global.LOW_POWER_MODE_TRIGGER_LEVEL的變化,接著調(diào)用mReceiver.init()方法,如下:
圖 39注冊一個action包含Intent.ACTION_BATTERY_CHANGED的廣播接收器,監(jiān)聽電量的變化。然后調(diào)用updateSaverMode()方法:
如上圖,updateSaverMode()的**終實現(xiàn)也是很簡單,根據(jù)不同狀態(tài)顯示不同的notification。這就是PowerUI主要的功能,關(guān)于PowerUI本文就描述到這里,如果讀者對PowerUI的更多細節(jié)感興趣,可參考相關(guān)資料。
3.4、任務(wù)管理
任務(wù)管理即Recents,代碼路徑在SystemUI/recents。Recents是手機設(shè)備基本和常用的功能,主要功能表現(xiàn)為:展示所有任務(wù),可以進行任務(wù)切換,可以進行任務(wù)的清除。同樣Recents是SystemUI類的子類,同樣啟動時從start()方法開始啟動。
Recents的start()方法很簡潔,主要是sAlternateRecents.onStart()方法,sAlternateRecent是AlternateRecentsComponent的實例,AlternateRecentsComponent作為一個組件服務(wù),擔負著管理Recents的變化過程,AlternateRecentsComponent是單例設(shè)計模式,但一般sAlternateRecent只創(chuàng)建一次,過程如下:
圖 42**getRecentsComponent()方法new一個AlternateRecentsComponent的對象實例,forceInitialize值是false,AlternateRecentsComponent實例化是會執(zhí)行圖43中的RecentsTaskLoader.initialize()方法實例化RecentsTaskLoader,RecentsTaskLoader是Recents讀取器。接著又new一個SystemServicesProxy的實例,mSystemServicesProxy具有ActivityManage和PackageManage的功能,在讀取Recents發(fā)揮了很重要的作用?;仡^看RecentsTaskLoader.initialize()的方法:
在RecentsTaskLoader.initialize()的方法中,除了實例化RecentsTaskLoader自己的同時,在RecentsTaskLoader的構(gòu)造函數(shù)中同時實例化比較重要的兩個變量,一個是TaskResourceLoadQueue,Recents資源隊列,另外一個是TaskResourceLoader,Recents的資源讀取器。下面根據(jù)SystemUI(Recents)的啟動過程了解這些類的作用。 在大多設(shè)備當中,**長按HOME鍵打開任務(wù)管理器,HOME長按事件觸發(fā)由輸入輸出事件派發(fā)者派發(fā)到系統(tǒng)進程(system_process)后被WindowManagerService攔截派發(fā)到PhoneWindowManager,如圖:
上圖中handleLongPressOnHome()將事件進一步發(fā)送到StatusBarManagerService,如圖:
StatusBarManagerService**CommandQueue發(fā)送到SystemUI進程,關(guān)于StatusBarManagerService和CommandQueue在StatusBar service中論述。**后發(fā)送到AlternateRecentsComponent,如圖:
到圖47,事件經(jīng)過了幾個進程,終于到準備啟動任務(wù)管理器的界面了,topTask是ActivityManager.RunningTaskInfo的實例,即正在系統(tǒng)運行的Activity,第二參數(shù)值為true。RecentsActivity啟動回調(diào)onCreate()方法:
onCreate()方法完成了實例化RecentsTaskLoader、SystemServicesProxy、RecentsConfiguration,在前面的內(nèi)容已提到,RecentsTaskLoader.initialize()方法同時實例化TaskResourceLoader和TaskResourceLoadQueue,然后注冊一個監(jiān)聽Intent.ACTION_SCREEN_OFF action的廣播接收器,即當屏幕熄滅后關(guān)閉RecentsActivity。RecentsActivity還復(fù)寫了onStart()方法:
上圖AlternateRecentsComponent.notifyVisibilityChanged(this, ssp, true)通知StatusBar RecentsActivity已經(jīng)起來,StatusBar需要配合做相應(yīng)的調(diào)整,之后調(diào)用updateRecentsTasks(),由于篇幅問題,下文將重點描述Tasks的管理,不再跟隨代碼的執(zhí)行流程。 RecentsTasks的管理過程主要包括讀取task,讀取task資源,顯示在RecentsActivity上,清除task。主要包括下面這些類: SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.ActivityInfoHandle SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader. TaskResourceLoadQueue SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader. TaskResourceLoader SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.Options RecentsTaskLoader是一個管理者,RecentsTaskLoader持有TaskResourceLoader,TaskResourceLoadQueue等實例,可以創(chuàng)建RecentsTaskLoadPlan實例,所以RecentsTaskLoader實質(zhì)并沒有去取讀取task和task資源,只是負責發(fā)起讀取task任務(wù)。ActivityInfoHandle 唯一持有一個AcitivityInfo的對象,保存Activity的信息,Activity的信息會在RecentsTaskLoadPlan中被查詢。TaskResourceLoader 負責task的資源讀取,和RecentsTaskLoader一樣,它是一個管理者,實質(zhì)實現(xiàn)讀取task資源的是TaskResourceLoadQueue 。RecentsTaskLoadPlan對象實例也是被RecentsTaskLoader持有,實質(zhì)上RecentsTaskLoadPlan是task讀取的參與者和實現(xiàn)者,Options 是RecentsTaskLoadPlan的內(nèi)部類,主要功能是控制RecentsTaskLoadPlan的讀取task的條件。RecentsTaskLoadPlan讀取task主要分兩個階段,**個個階段是 上圖中l(wèi)oader是RecentsTaskLoader的實例,調(diào)用preloadTasks()方法,即task讀取的**階段,plan是RecentsTaskLoadPlan的實例,第二個參數(shù)mConfig.launchedFromHome是boolean值,作用是isTopTaskHome,在啟動RecentsActivity之前被賦值。這個階段主要完成對task的讀取。第二個階段是: 上圖中l(wèi)oadTasks()方法就是啟動RecentsTaskLoadPlan的第二個階段,同上圖50,loader是RecentsTaskLoader的實例,**個參數(shù)this是Context的實例,plan是RecentsTaskLoadPlan的實例,loadOpts是Options的實例,loadOpts在這里的作用是控制RecentsTaskLoadPlan讀取task的規(guī)則,第二個階段必須基于**個階段,也就是說在調(diào)用loadTasks()方法前,必須先執(zhí)行preloadTasks()方法,loadTasks()基于preloadTasks()中讀取到的task,從task中讀取task的資源。 這兩個階段緊密連連,有先有后,完成不同的功能,下文將具體描述這兩個階段的過程。Loader. preloadTasks()實質(zhì)調(diào)用RecentsTaskLoadPlan的如下方法 在這里會實例化一個TaskStack的對象實例,TaskStack封裝了包含List類型的類,TaskStack包含兩種類型的List,一種是存儲所有的task,一種是filter task list,同時提供一個TaskFilter工具類接口,過濾主要**PakcageName作為匹配。然后調(diào)用preloadRawTasks()方法實例化mRawTasks,mRawTasks是一個ListActivityManager.RecentTaskInfo>實例,mRawTasks存儲了RecentTaskInfo類型的實例,所以mRawTasks是讀取task的關(guān)鍵,看mRawTasks的實例化過程 上圖中mSystemServicesProxy是SystemServicesProxy的實例,調(diào)用圖中的方法,再往下看 上圖中mAm是ActivityManager的實例,getRecentTasksForUser()方法實質(zhì)是**binder調(diào)用了遠程的ActivityManagerService的方法,關(guān)于getRecentTasksForUser()這個方法在ActivityManagerService中的實現(xiàn),讀者可以自行閱讀。在這里得到一個ListActivityManager.RecentTaskInfo>的對象實例tasks,RecentTaskInfo實質(zhì)包含什么數(shù)據(jù)呢?如圖 上圖中是RecentTaskInfo的變量,得到這些數(shù)據(jù),回到前面圖52的地方,看下圖
上圖中獲取到RecentTaskInfo后,把信息重新打包封裝到TaskKey中,然后讀取Activity的名字,Acitivity的圖標,和thumbnail,然后把數(shù)據(jù)保存到TaskStack中。到此,**個階段就完成了,在這個階段完成了讀取task的基本信息RecentTaskInfo,然后讀取Activity的基本信息ActivityInfo,把數(shù)據(jù)保存到TaskStack中。 回到圖50,**階段完成后,接著就行圖51中的第二階段loader.loadTasks(),如下圖
上圖可以看到,這里獲取icon和thumbnail都是在**個階段就已經(jīng)完成了動作,在這里在根據(jù)inRunningTask等條件再次刷新數(shù)據(jù)罷了。 到這里task和task資源讀取完成,上上文中提到TaskResourceLoadQueue和TaskResourceLoader,這兩個類在RecentsTaskLoadPlan的兩個階段都有使用,用于異步讀取Activity Icon,TaskResourceLoadQueue會管理這些任務(wù)。 所有的Task數(shù)據(jù)到這里已準備就緒,接下下就是把數(shù)據(jù)顯示在Activity上(屏幕上),對于數(shù)據(jù)怎樣綁定到View,本文不再論述。
3.5、存儲通知
存儲通知即StorageNotification service,在SystemUI中主要完成對存儲器變化的通知,即USB連接的變化,存儲器的變化SystemUI發(fā)送相應(yīng)的Notification。StorageNotification的啟動如下:
StorageNotification的啟動很簡單,創(chuàng)建一個StorageNotification-EventListener的實例,把StorageNotificationEventListener**StorageManager注冊到到MountService。當USB連接或存儲器發(fā)生變化是遠程回調(diào)到StorageNotificationEventListener的方法,如下圖:
USB變化回調(diào)到onUsbMassStorageConnectionChangedAsync()進行處理,存儲器發(fā)生變化回調(diào)到onStorageStateChangedAsync()處理,就是在發(fā)送notification通知USB和存儲器的變化。這個模塊本文就論述到這里,在SystemUI中StorageNotification結(jié)構(gòu)清晰,功能簡單,讀者感興趣可以自行了解。
3.6、鎖屏
鎖屏(Keyguard)service在SystemUI是一個比較特殊的模塊,特殊在于SystemUI啟動的service只是一個信息傳遞者,也就是KeyguardViewMediator,并沒有做鎖屏或解屏的實質(zhì)操作。在這里,涉及到三個比較關(guān)鍵的類是: /SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java /SystemUI/src/com/android/systemui/keyguard/KeyguardService.java Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java KeyguardViewMediator和KeyguardService在源碼中位于同一個GIT庫(SystemUI)中,而KeyguardUpdateMonitor則位于KeyGuard庫中。在KeyguardViewMediator的初始化中主要做了三件事,如圖
實例化KeyguardUpdateMonitor的實例mUpdateMonitor,KeyguardUpdateMonitor負責更新已經(jīng)鎖屏界面上的內(nèi)容,如時間,當然,KeyguardUpdateMonitor只是一個信息傳遞著,實際去刷新界面的是StatusBar模塊。Keyguard模塊通知StatusBar刷新解密那**KeyguardUpdateMonitorCallback這個類就行遠程回調(diào),該類的實例在StatusBar模塊啟動時**KeyguardService獲取到IKeyguardService的遠端實例,**IKeyguardService遠程調(diào)用IKeyguardService的addStateMonitorCallback()方法實例化KeyguardUpdateMonitorCallback對象,如下圖
SystemUI啟動的Keyguard模塊并沒有真正的去操作鎖屏界面,而是作為一個信息傳遞著把信息傳遞給StatusBar模塊。這個模塊本文就介紹到這里。
3.7、通知欄
通知欄(SystemBars)service是SystemUI中**重要的service,代碼量**多,**復(fù)雜的,界面結(jié)構(gòu)也復(fù)雜。根據(jù)前面的內(nèi)容可知,啟動SystemBars是**調(diào)用start()方法,如下圖:
這里實質(zhì)是回調(diào)到到SystemBars的onNoService()方法(這里涉及到安全設(shè)置啟動的模式不一樣,本文只討論正常模式),**后是調(diào)用SystemBars的createStatusBarFromConfig()方法
上圖可以看到,從string資源文件里面讀取class name,**java的映射機制實例化對象,然后調(diào)用start()方法啟動,class name的值如下圖: 該配置文件在SystemUI/res/values/config.xml中。所以實質(zhì)是PhoneStatusBar調(diào)用了start()方法。 SystemBars模塊本文分兩個階段論述,**階段是SystemBars的初始化過程,第二階段是Notification的顯示過程。**階段主要涉及的類是: SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java PhoneStatusBar的父類是BaseStatusBar繼承于SystemUI,上文提到,SystemBars調(diào)用PhoneStatusBar中的start()方法,下面跟隨代碼看看這個過程。
如上圖,調(diào)用父類中的start()方法,即BaseStatsuBar中的start()方法。然后調(diào)用addNavigationBar()方法實例化導(dǎo)航條,這里不再贅述此功能。繼續(xù)看BaseStatsuBar中的方法。
如上圖BaseStatsuBar中的start()方法,實例化一個StatusBarIconList的對象,此處iconList對象是“空值”,然后**IStatusBarService的實例mBarService對象注冊到StatusBarManager?Service。mCommandQueue是CommandQueue的實例,在Status?Bar-ManagerService的遠程回調(diào),實現(xiàn)StatusBarManagerService和SystemUI的通信。然后調(diào)用createAndAddWindows()方法,方法初始化status bar,notification,quick settings等的View控件。在這里,還需要注意NotificationListenerService的實例mNotificationListener的registerAsSystemService()方法,該方法主要實現(xiàn)StatusBarManagerService和SystemUI的notification的控制通道,也就是說,StatusBarManagerService收到notification變化時,**此通道通知SystemUI顯示notification的變化。下文將介紹notification從StatusBarManagerService到SystemUI的過程。 一個APP需要顯示notification首先需要實例化一個NotificationManager的對象,然后調(diào)用NotificationManager的方法notify()方法把創(chuàng)建好的Notification對象作為參數(shù)傳進去。
上圖中可以看到一個service的對象調(diào)用了enqueueNotification-WithTag()方法,該方法實質(zhì)是遠程調(diào)用NotificationManagerService中的enqueueNotificationWithTag()方法,該方法如下:
這里會把NotificationManager傳遞過來的Notification對象進行很多處理,比如變換成NotificationRecord,實質(zhì)就是把Notification緩存下來。在上圖的這個過程,還有一些其它的處理邏輯,在這里就不詳細說明了,讀者可以自行了解。上圖中在代碼的末尾調(diào)用了buzzBeepBlinkLocked()方法,該方法主要處理Notification的聲音和震動的邏輯,本文也不再詳述。接著看mListeners調(diào)用了notifyPostedLocked()方法,此方法**終會執(zhí)行到如下圖的代碼
首先留意上圖中final INotificationListener listener = (INotificationListener)info.service;這句代碼,info.service返回一個INotificationListener的實例對象,該對象在上文中圖66中的mNotificationListener.registerAsSystemService()方法進行設(shè)置,所以listener.onNotificationPosted()方法實質(zhì)是遠程回調(diào)SystemUI中的方法,如下圖
如上圖,這里又調(diào)用了Notification.Builder.rebuild()方法,該方法主要把**Binder機制傳遞過來的數(shù)據(jù)重新組裝一些顯示View所需要的數(shù)據(jù),如notification的布局文件等等。重新組裝notification數(shù)據(jù)后,調(diào)用NotificationListenerService.this.onNotificationPosted()方法,然后代碼會執(zhí)行到BaseStatusBar中的如下代碼
上圖中,代碼運行又回到熟悉的BaseStatusBar.java類中,從APP調(diào)用NotificationManager的notify()方法到BaseStatusBar的addNotification()或updateNotification()方法,經(jīng)歷了一個復(fù)雜的過程,涉及的模塊多,模塊交互復(fù)雜。到此,本文就不再往下詳情說明Notification到達SystemUI的處理過程了,讀者感興趣可自行閱讀代碼。
4、總結(jié)
本文詳細描述了SystemUI中KeyguardViewMediator、Recents、VolumeUI、SystemBars、StorageNotification、PowerUI、RingtonePlayer 7個模塊(SERVICE),其中SystemBars是SystemUI中起到中樞作用的一個模塊,因為這個模塊和其他模塊交互**緊密,而且SystemUI中大多數(shù)UI的View都是在SystemBars中初始化和控制顯示。不過,SystemUI的功能不止本文中說論述到的,SystemUI還有例如情景模式控制、流量警告和常用的屏幕截屏等功能,本文不再去說明它們,讀者可自行去研究SystemUI中的每個功能。
相關(guān)推薦:
熱門課程
機構(gòu)資訊
- 太倉java開發(fā)培訓(xùn)費用_太倉JAVA培訓(xùn)
- 昆山哪里有Java實戰(zhàn)培訓(xùn)學校_昆山JAVA培訓(xùn)
- 常熟學Java哪個好_常熟JAVA培訓(xùn)
- 蘇州Java培訓(xùn)課程哪個好_蘇州JAVA培訓(xùn)
- 昆山哪里有Java語言培訓(xùn)學院_昆山JAVA培訓(xùn)
- 昆山Java工程師培訓(xùn)機構(gòu)哪個好_昆山JAVA培訓(xùn)
- 常熟學習Java工程師哪里好_常熟JAVA培訓(xùn)
- 昆山Java編程課程價格_昆山JAVA培訓(xùn)
- 張家港Java開發(fā)培訓(xùn)班學費_張家港JAVA培訓(xùn)
- 太倉Java工程師培訓(xùn)學院哪里好_太倉JAVA培訓(xùn)