五翩剪、重點機制原理
1坡慌、Handler機制
問題:handler機制介紹
1.MessageQueue:讀取會自動刪除消息溢吻,單鏈表維護川梅,在插入和刪除上有優(yōu)勢歼狼。在其next()中會無限循環(huán)诀蓉,不斷判斷是否有消息萍嬉,有就返回這條消息并移除耐床。
2.Looper:Looper創(chuàng)建的時候會創(chuàng)建一個MessageQueue澜公,調用loop()方法的時候消息循環(huán)開始冕末,loop()也是一個死循環(huán)萍歉,會不斷調用messageQueue的next(),當有消息就處理档桃,否則阻塞在messageQueue的next()中枪孩。當Looper的quit()被調用的時候會調用messageQueue的quit(),此時next()會返回null,然后loop()方法也跟著退出胳蛮。
3.Handler:在主線程構造一個Handler销凑,然后在其他線程調用sendMessage(),此時主線程的MessageQueue中會插入一條message,然后被Looper使用仅炊。
4.系統(tǒng)的主線程在ActivityThread的main()為入口開啟主線程斗幼,其中定義了內部類Activity.H定義了一系列消息類型,包含四大組件的啟動停止抚垄。
Handler通過調用sendmessage方法把消息放在消息隊列MessageQueue中蜕窿,Looper負責把消息從消息隊列中取出來,重新再交給Handler進行處理呆馁,三者形成一個循環(huán)
通過構建一個消息隊列桐经,把所有的Message進行統(tǒng)一的管理,當Message不用了浙滤,并不作為垃圾回收阴挣,而是放入消息隊列中,供下次handler創(chuàng)建消息時候使用纺腊,提高了消息對象的復用畔咧,減少系統(tǒng)垃圾回收的次數(shù)
每一個線程茎芭,都會單獨對應的一個looper,這個looper通過ThreadLocal來創(chuàng)建誓沸,保證每個線程只創(chuàng)建一個looper梅桩,looper初始化后就會調用looper.loop創(chuàng)建一個MessageQueue,這個方法在UI線程初始化的時候就會完成拜隧,我們不需要手動創(chuàng)建
問題:Android為什么只能在主進程中更新UI宿百?主線程有Looper的死循環(huán)為什么不會卡死。
關于Android中為什么主線程不會因為Looper.loop()里的死循環(huán)卡死洪添?引發(fā)的思考垦页,事實可能不是一個 epoll 那么 簡單。
2干奢、HandlerThread理解
3外臂、View事件分發(fā)機制及整個流程
問題:介紹觸摸事件的分發(fā)機制
(1) 事件從Activity.dispatchTouchEvent()開始傳遞,只要沒有被停止或攔截律胀,從最上層的View(ViewGroup)開始一直往下(子View)傳遞。子View可以通過onTouchEvent()對事件進行處理貌矿。
(2) 事件由父View(ViewGroup)傳遞給子View炭菌,ViewGroup可以通過onInterceptTouchEvent()對事件做攔截,停止其往下傳遞逛漫。
(3) 如果事件從上往下傳遞過程中一直沒有被停止黑低,且最底層子View沒有消費事件,事件會反向往上傳遞酌毡,這時父View(ViewGroup)可以進行消費克握,如果還是沒有被消費的話,最后會到Activity的onTouchEvent()函數(shù)枷踏。
(4) 如果View沒有對ACTION_DOWN進行消費菩暗,之后的其他事件不會傳遞過來。
(5) OnTouchListener優(yōu)先于onTouchEvent()對事件進行消費旭蠕。
上面的消費即表示相應函數(shù)返回值為true停团。
問題:View中 setOnTouchListener的onTouch,onTouchEvent掏熬,onClick的執(zhí)行順序
追溯到View的dispatchTouchEvent源碼查看佑稠,有這么一段代碼
public boolean dispatchTouchEvent(MotionEvent event) {
if (!onFilterTouchEventForSecurity(event)) {
return false;
}
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event);
}
當以下三個條件任意一個不成立時,
mOnTouchListener不為null
view是enable的狀態(tài)
mOnTouchListener.onTouch(this, event)返回true旗芬,
函數(shù)會執(zhí)行到onTouchEvent舌胶。在這里我們可以看到,首先執(zhí)行的是mOnTouchListener.onTouch的方法疮丛,然后是onTouchEvent方法
繼續(xù)追溯源碼幔嫂,到onTouchEvent()觀察辆它,發(fā)現(xiàn)在處理ACTION_UP事件里有這么一段代碼
if (!post(mPerformClick)) {
performClick();
}
此時可知,onClick方法也在最后得到了執(zhí)行
所以三者的順序是:
setOnTouchListener() 的onTouch
onTouchEvent()
onClick()
4婉烟、View繪制機制和加載過程
measure()方法娩井,layout(),draw()三個方法主要存放了一些標識符似袁,來判斷每個View是否需要再重新測量洞辣,布局或者繪制,主要的繪制過程還是在onMeasure昙衅,onLayout扬霜,onDraw這個三個方法中
1.onMesarue()為整個View樹計算實際的大小,即設置實際的高(對應屬性:mMeasuredHeight)和寬(對應屬性: mMeasureWidth)而涉,每個View的控件的實際寬高都是由父視圖和本身視圖決定的著瓶。
2.onLayout()為將整個根據(jù)子視圖的大小以及布局參數(shù)將View樹放到合適的位置上。
3. onDraw()開始繪制圖像啼县,繪制的流程如下
首先繪制該View的背景
調用onDraw()方法繪制視圖本身 (每個View都需要重載該方法材原,ViewGroup不需要實現(xiàn)該方法)
如果該View是ViewGroup,調用dispatchDraw ()方法繪制子視圖
繪制滾動條
5季眷、Binder機制
MS思考:Android面試一天一題(Day 35:神秘的Binder機制)
1.在Activity和Service進行通訊的時候余蟹,用到了Binder。
1.當屬于同個進程我們可以繼承Binder然后在Activity中對Service進行操作
2.當不屬于同個進程子刮,那么要用到AIDL讓系統(tǒng)給我們創(chuàng)建一個Binder威酒,然后在Activity中對遠端的Service進行操作。
2.系統(tǒng)給我們生成的Binder:
1.Stub類中有:接口方法的id挺峡,有該Binder的標識葵孤,有asInterface(IBinder)(讓我們在Activity中獲取實現(xiàn)了Binder的接口,接口的實現(xiàn)在Service里橱赠,同進程時候返回Stub否則返回Proxy)尤仍,有onTransact()這個方法是在不同進程的時候讓Proxy在Activity進行遠端調用實現(xiàn)Activity操作Service
2.Proxy類是代理,在Activity端病线,其中有:IBinder mRemote(這就是遠端的Binder)吓著,兩個接口的實現(xiàn)方法不過是代理最終還是要在遠端的onTransact()中進行實際操作。
3.哪一端的Binder是副本送挑,該端就可以被另一端進行操作绑莺,因為Binder本體在定義的時候可以操作本端的東西。所以可以在Activity端傳入本端的Binder惕耕,讓Service端對其進行操作稱為Listener纺裁,可以用RemoteCallbackList這個容器來裝Listener,防止Listener因為經(jīng)歷過序列化而產(chǎn)生的問題。
4.當Activity端向遠端進行調用的時候欺缘,當前線程會掛起栋豫,當方法處理完畢才會喚醒。
5.如果一個AIDL就用一個Service太奢侈谚殊,所以可以使用Binder池的方式丧鸯,建立一個AIDL其中的方法是返回IBinder,然后根據(jù)方法中傳入的參數(shù)返回具體的AIDL嫩絮。
6.IPC的方式有:Bundle(在Intent啟動的時候傳入丛肢,不過是一次性的),文件共享(對于SharedPreference是特例剿干,因為其在內存中會有緩存)蜂怎,使用Messenger(其底層用的也是AIDL,同理要操作哪端置尔,就在哪端定義Messenger)杠步,AIDL,ContentProvider(在本進程中繼承實現(xiàn)一個ContentProvider榜轿,在增刪改查方法中調用本進程的SQLite幽歼,在其他進程中查詢),Socket
6谬盐、跨進程通信(AIDL及其它) --1
MS思考:Android面試一天一題(Day 36:AIDL)
分析篇:AIDL的使用情況和實例介紹
問題:Android 進程間的通信有哪幾種方式
Bundle/Intent傳遞數(shù)據(jù)助析,Messenger(消息隊列適合單線程,底層還是AIDL)椅您,AIDL外冀,ContentProvider,Socket
問題:Bundle掀泳、文件共享雪隧、ContentProvider、AIDL的使用場景
7员舵、異步任務機制之AsycTask
問題:AsyncTask原理及不足
問題:AsynTask為什么要設計為只能夠一次任務?
最核心的還是線程安全問題脑沿,多個子線程同時運行,會產(chǎn)生狀態(tài)不一致的問題马僻。所以要務必保證只能夠執(zhí)行一次
問題:AsynTask造成的內存泄露的問題怎么解決庄拇,比如非靜態(tài)內部類AsynTask會隱式地持有外部類的引用,如果其生命周期大于外部activity的生命周期,就會出現(xiàn)內存泄漏
注意要復寫AsynTask的onCancel方法措近,把里面的socket溶弟,file等,該關掉的要及時關掉
在 Activity 的onDestory()方法中調用Asyntask.cancal方法
Asyntask內部使用弱引用的方式來持有Activity
問題:若Activity已經(jīng)銷毀瞭郑,此時AsynTask執(zhí)行完并且返回結果辜御,會報異常嗎?
當一個App旋轉時,整個Activity會被銷毀和重建屈张。當Activity重啟時擒权,AsyncTask中對該Activity的引用是無效的,因此onPostExecute()就不會起作用袜茧,若AsynTask正在執(zhí)行菜拓,折會報 view not attached to window manager 異常
同樣也是生命周期的問題,在 Activity 的onDestory()方法中調用Asyntask.cancal方法笛厦,讓二者的生命周期同步
問題:Activity銷毀但Task如果沒有銷毀掉纳鼎,當Activity重啟時這個AsyncTask該如何解決?
還是屏幕旋轉這個例子裳凸,在重建Activity的時候贱鄙,會回掉Activity.onRetainNonConfigurationInstance()重新傳遞一個新的對象給AsyncTask,完成引用的更新
問題:AstncTask+HttpClient與AsyncHttpClient有什么區(qū)別
8姨谷、Android啟動過程及應用啟動過程--1
分析篇:Android啟動過程圖解
問題:Android窗口設計
問題:activity啟動過程
1.Activity中最終到startActivityForResult()(mMainThread.getApplicationThread()傳入了一個ApplicationThread檢查APT)
->Instrumentation#execStartActivity()和checkStartActivityResult()(這是在啟動了Activity之后判斷Activity是否啟動成功逗宁,例如沒有在AM中注冊那么就會報錯)
->ActivityManagerNative.getDefault().startActivity()(類似AIDL,實現(xiàn)了IAM梦湘,實際是由遠端的AMS實現(xiàn)startActivity())
->ActivityStackSupervisor#startActivityMayWait()
->ActivityStack#resumeTopActivityInnerLocked
->ActivityStackSupervisor#realStartActivityLocked()(在這里調用APT的scheduleLaunchActivity,也是AIDL瞎颗,不過是在遠端調起了本進程Application線程)
->ApplicationThread#scheduleLaunchActivity()(這是本進程的一個線程,用于作為Service端來接受AMS client端的調起)
->ActivityThread#handleLaunchActivity()(接收內部類H的消息捌议,ApplicationThread線程發(fā)送LAUNCH_ACTIVITY消息給H)
->最終在ActivityThread#performLaunchActivity()中實現(xiàn)Activity的啟動完成了以下幾件事:
2.從傳入的ActivityClientRecord中獲取待啟動的Activity的組件信息
3.創(chuàng)建類加載器哼拔,使用Instrumentation#newActivity()加載Activity對象
4.調用LoadedApk.makeApplication方法嘗試創(chuàng)建Application,由于單例所以不會重復創(chuàng)建瓣颅。
5.創(chuàng)建Context的實現(xiàn)類ContextImpl對象倦逐,并通過Activity#attach()完成數(shù)據(jù)初始化和Context建立聯(lián)系,因為Activity是Context的橋接類宫补,
最后就是創(chuàng)建和關聯(lián)window檬姥,讓Window接收的事件傳給Activity,在Window的創(chuàng)建過程中會調用ViewRootImpl的performTraversals()初始化View粉怕。
6.Instrumentation#callActivityOnCreate()->Activity#performCreate()->Activity#onCreate().onCreate()中會通過Activity#setContentView()調用PhoneWindow的setContentView()
更新界面健民。
術語:
1.ActivityManagerServices,簡稱AMS贫贝,服務端對象荞雏,負責系統(tǒng)中所有Activity的生命周期
2.ActivityThread,App的真正入口。當開啟App之后凤优,會調用main()開始運行悦陋,開啟消息循環(huán)隊列,這就是傳說中的UI線程或者叫主線程筑辨。與ActivityManagerServices配合俺驶,一起完成Activity的管理工作
3.ApplicationThread,用來實現(xiàn)ActivityManagerService與ActivityThread之間的交互棍辕。在ActivityManagerService需要管理相關Application中的Activity的生命周期時暮现,通過ApplicationThread的代理對象與ActivityThread通訊。
4.ApplicationThreadProxy楚昭,是ApplicationThread在服務器端的代理栖袋,負責和客戶端的ApplicationThread通訊。AMS就是通過該代理與ActivityThread進行通信的抚太。
5.Instrumentation塘幅,每一個應用程序只有一個Instrumentation對象,每個Activity內都有一個對該對象的引用尿贫。Instrumentation可以理解為應用進程的管家电媳,ActivityThread要創(chuàng)建或暫停某個Activity時,都需要通過Instrumentation來進行具體的操作庆亡。
6.ActivityStack匾乓,Activity在AMS的棧管理,用來記錄已經(jīng)啟動的Activity的先后關系又谋,狀態(tài)信息等拼缝。通過ActivityStack決定是否需要啟動新的進程。
7.ActivityRecord彰亥,ActivityStack的管理對象珍促,每個Activity在AMS對應一個ActivityRecord,來記錄Activity的狀態(tài)以及其他的管理信息剩愧。其實就是服務器端的Activity對象的映像。
8.TaskRecord娇斩,AMS抽象出來的一個“任務”的概念仁卷,是記錄ActivityRecord的棧,一個“Task”包含若干個ActivityRecord犬第。AMS用TaskRecord確保Activity啟動和退出的順序锦积。如果你清楚Activity的4種launchMode,那么對這個概念應該不陌生歉嗓。
9丰介、Loader機制
10、安卓權限管理
11、Dalvik及ART虛擬機系列問題
問題:什么是Dalvik虛擬機哮幢?
Dalvik虛擬機是Android平臺的核心带膀。它可以支持.dex格式的程序的運行,.dex格式是專為Dalvik設計的一種壓縮格式橙垢,可以減少整體文件尺寸垛叨,提高I/O操作的速度,適合內存和處理器速度有限的系統(tǒng)柜某。
問題:Dalvik虛擬機的作用是什么嗽元?
Dalvik虛擬機主要是完成對象生命周期管理,內存回收喂击,堆棧管理剂癌,線程管理,安全和異常管理等等重要功能翰绊。
問題:Dalvik虛擬機與JVM有什么區(qū)別
主要區(qū)別:
Dalvik是基于寄存器的佩谷,而JVM是基于棧的。
Dalvik運行dex文件辞做,而JVM運行java字節(jié)碼
自Android 2.2開始琳要,Dalvik支持JIT(just-in-time,即時編譯技術)秤茅。
優(yōu)化后的Dalvik較其他標準虛擬機存在一些不同特性:
1.占用更少空間
2.為簡化翻譯稚补,常量池只使用32位索引
3.標準Java字節(jié)碼實行8位堆棧指令,Dalvik使用16位指令集直接作用于局部變量。局部變量通常來自4位的“虛擬寄存器”區(qū)框喳。這樣減少了Dalvik的指令計數(shù)课幕,提高了翻譯速度。
當Android啟動時五垮,Dalvik VM 監(jiān)視所有的程序(APK)乍惊,并且創(chuàng)建依存關系樹,為每個程序優(yōu)化代碼并存儲在Dalvik緩存中放仗。Dalvik第一次加載后會生成Cache文件润绎,以提供下次快速加載,所以第一次會很慢诞挨。
Dalvik解釋器采用預先算好的Goto地址莉撇,每個指令對內存的訪問都在64字節(jié)邊界上對齊。這樣可以節(jié)省一個指令后進行查表的時間惶傻。為了強化功能, Dalvik還提供了快速翻譯器(Fast Interpreter)棍郎。
一般來說,基于堆棧的機器必須使用指令才能從堆棧上的加載和操作數(shù)據(jù),因此,相對基于寄存器的機器,它們需要更多的指令才能實現(xiàn)相同的性能银室。但是基于寄存器機器上的指令必須經(jīng)過編碼,因此,它們的指令往往更大涂佃。
Dalvik虛擬機既不支持Java SE 也不支持Java ME類庫(如:Java類,AWT和Swing都不支持)励翼。 相反,它使用自己建立的類庫(Apache Harmony Java的一個子集)。
問題:每個應用程序對應多少個Dalvik虛擬機
每一個Android應用在底層都會對應一個獨立的Dalvik虛擬機實例辜荠,其代碼在虛擬機的解釋下得以執(zhí)行 汽抚,而所有的Android應用的線程都對應一個Linux線程
問題:Art和Dalvik對比;大致工作流程侨拦。兩者有什么區(qū)別?
ART 的機制與 Dalvik 不同殊橙。在Dalvik下,應用每次運行的時候狱从,字節(jié)碼都需要通過即時編譯器(just in time 膨蛮,JIT)轉換為機器碼,這會拖慢應用的運行效率季研,而在ART 環(huán)境中敞葛,應用在第一次安裝的時候,字節(jié)碼就會預先編譯成機器碼与涡,使其成為真正的本地應用惹谐。這個過程叫做預編譯(AOT,Ahead-Of-Time)。這樣的話驼卖,應用的啟動(首次)和執(zhí)行都會變得更加快速氨肌。
問題:虛擬機原理,
問題:如何自己設計一個虛擬機(內存管理酌畜,類加載怎囚,雙親委派);
問題:JVM內存模型及類加載機制桥胞;
問題:內存對象的循環(huán)引用及避免
在Ios中比較常見恳守,用assign而不是retain聲明屬性可以避免循環(huán)引用,ARC下用弱引用也可以解決
12贩虾、Window和WindowManager機制
1.Window用于顯示View和接收各種事件催烘,Window有三種類型:應用Window(每個Activity對應一個Window)、子Window(不能單獨存在缎罢,附屬于特定Window)伊群、系統(tǒng)window(Toast和狀態(tài)欄)
2.Window分層級,應用Window在1-99策精、子Window在1000-1999舰始、系統(tǒng)Window在2000-2999.WindowManager提供了增刪改View三個功能。
3.Window是個抽象概念:每一個Window對應著一個View和ViewRootImpl蛮寂,Window通過ViewRootImpl來和View建立聯(lián)系,View是Window存在的實體易茬,只能通過WindowManager來訪問Window酬蹋。
4.WindowManager的實現(xiàn)是WindowManagerImpl其再委托給WindowManagerGlobal來對Window進行操作及老,其中有四個List分別儲存對應的View、ViewRootImpl范抓、WindowManger.LayoutParams和正在被刪除的View
5.Window的實體是存在于遠端的WindowMangerService中骄恶,所以增刪改Window在本端是修改上面的幾個List然后通過ViewRootImpl重繪View,通過WindowSession(每個應用一個)在遠端修改Window匕垫。
6.Activity創(chuàng)建Window:Activity會在attach()中創(chuàng)建Window并設置其回調(onAttachedToWindow()僧鲁、dispatchTouchEvent()),Activity的Window是由Policy類創(chuàng)建PhoneWindow實現(xiàn)的。然后通過Activity#setContentView()調用PhoneWindow的setContentView象泵。