關於安卓進階面試題
ThreadLocal作用以及原理?
ThreadLocal用於實現在不同的執行緒中儲存執行緒私有資料的類。在多執行緒的環境中,當多個執行緒需要對某個變數進行頻繁操作,同時各個執行緒間不需要同步。此時,各個子執行緒只需要對儲存在當前執行緒中的變數的拷貝進行操作即可,程式的執行效率會很高,即所謂的空間換時間。
原理:在當前執行緒中呼叫get方法時,通過ThreadLocal的initialValue方法建立當前執行緒的一個本地資料拷貝,將此拷貝新增到當前執行緒本地資料的table陣列當中;或者在呼叫set方法時,將當前執行緒的本地資料儲存到當前執行緒的table陣列中.當前執行緒通過呼叫ThreadLocal物件的get方法即得到當前執行緒本地資料物件。
請簡要描述一下View事件傳遞分發機制
事件的傳遞順序 Activity -> Window -> View。
事件分發的關鍵函式:
dispatchTouchEvent、onInterceptTouchEvent和onTouchEvent。
dispatchTouchEvent:用於事件的分發,如果事件傳遞到View層級,則一定會呼叫此函式。函式的返回結果受當前View的onTouchEvent方法和處於下一層級View的dispatchTouchEvent方法影響。
onInterceptTouchEvent:返回結果表示是否攔截此事件
onTouchEvent:用於處理事件,如果View決定攔截事件則在該函式中進行事件處理。
事件分發中的onTouch和onTouchEvent有什麼區別,又該如何使用?
onTouchListener的onTouch方法優先順序比onTouchEvent高,會先觸發。
若onTouch方法返回false則會接著觸發onTouchEvent,反之onTouchEvent方法不會被呼叫。
View和ViewGroup分別有哪些事件分發相關的回撥方法
dispatchTouchEvent、onInterceptTouchEvent和onTouchEvent。
View繪製流程
onMeasure:測量檢視的大小,從頂層父View到子View遞迴呼叫measure()方法,measure()呼叫onMeasure()方法,onMeasure()方法完成繪製工作。
onLayout:確定檢視的位置,從頂層父View到子View遞迴呼叫layout()方法,父View將上一步measure()方法得到的子View的佈局大小和佈局引數,將子View放在合適的位置上。
onDraw:繪製最終的檢視,首先ViewRoot建立一個Canvas物件,然後呼叫onDraw()方法進行繪製。onDraw()方法的繪製流程為:
繪製檢視背景-> 繪製畫布的圖層->繪製View內容->繪製子檢視。
如何取消AsyncTask?
呼叫cancel方法,傳遞訊號量。同時,在doInBackground中檢測當前狀態:當狀態是cancel狀態,則立刻跳出迴圈。
為什麼不能在子執行緒更新UI?
安卓系統的UI控制元件並非執行緒安全的,如果多執行緒併發訪問同一個UI控制元件時會引發UI控制元件狀態的混亂。
ANR產生的原因是什麼?
ANR的全稱是application not responding,意思就是程式未響應。
產生原因:
1.主執行緒執行了耗時操作,在一定時間內沒有響應操作。比如資料庫操作或網路程式設計。
2.其他程序(就是其他程式)佔用CPU導致本程序得不到CPU時間片,比如其他程序的頻繁讀寫操作可能會導致這個問題。
ANR定位和修正
可以通過檢視/data/anr/traces.txt檢視ANR資訊。根據日誌檔案的資訊提示修改程式碼。
OOM是什麼?
OOM,全稱“Out Of
Memory”,翻譯為“記憶體用盡”當JVM因為沒有足夠的記憶體來為物件分配空間並且垃圾回收器也已經沒有空間可回收時,就會丟擲OOM。
什麼情況導致OOM?
OOM常見情況:
1)Acitivity沒有對棧進行管理,如果開啟過多,就容易造成記憶體溢位 2)載入大的圖片或者同時數量過多的圖片的時候
3)程式存在記憶體洩漏問題,導致系統可用記憶體越來越小。 4)遞迴次數過多,也會導致記憶體溢位.
5)頻繁的記憶體抖動,也會造成OOM異常的發生,大量小的物件被頻繁的建立,導致記憶體碎片,從而當需要分配記憶體的時候,雖然總體上還有記憶體分配,但是由於這些記憶體不是連續的,導致無法分配,系統就直接返回OOM了
有什麼解決方法可以避免OOM?
1)減小物件的記憶體佔用,避免OOM的第一步就是要儘量減少新分配出來的物件佔用記憶體的大小,儘量使用更加輕量的物件。
2)記憶體物件的重複利用,大多數物件的複用,最終實施的方案都是利用物件池技術,要麼是在編寫程式碼時顯式地在程式裡建立物件池,然後處理好複用的實現邏輯。要麼就是利用系統框架既有的某些複用特性,減少物件的重複建立,從而降低記憶體的分配與回收。
3)避免物件的記憶體洩露,記憶體物件的洩漏,會導致一些不再使用的物件無法及時釋放,這樣一方面佔用了寶貴的記憶體空間,很容易導致後續需要分
配記憶體的時候,空閒空間不足而出現OOM。 4)記憶體使用策略優化。
OOM是否可以try catch?為什麼?
可以。在某些情況下,我們需要事先評估那些可能發生OOM的程式碼,對於這些可能發生OOM的程式碼,加入catch機制,可以考慮在catch裡面嘗試一次降級的記憶體分配操作。
記憶體洩漏是什麼?
記憶體洩漏(Memory
Leak)是指程式中己動態分配的堆記憶體由於某種原因程式未釋放或無法釋放,造成系統記憶體的浪費,導致程式執行速度減慢甚至系統崩潰等嚴重後果。
什麼情況導致記憶體洩漏?
常見情況:
1)單例造成的記憶體洩漏
由於單例的靜態特性使得其生命週期和應用的生命週期一樣長,如果一個物件已經不再需要使用了,而單例物件還持有該物件的引用,就會使得該物件不能被正常回收,從而導致了記憶體洩漏。
2)非靜態內部類建立靜態例項造成的記憶體洩漏
3)Handler造成的記憶體洩漏
當Activity結束時,未處理的訊息持有handler的引用,而handler又持有它所屬的外部類也就是MainActivity的引用。這條引用關係會一直保持直到訊息得到處理,這樣阻止了MainActivity被垃圾回收器回收,從而造成了記憶體洩漏。
4)執行緒造成的記憶體洩漏
若執行緒持有Activity的引用,且執行緒處於後臺執行狀態,當Activity銷燬但執行緒仍然存活且持有Activity的引用,則會引起記憶體洩漏。
5)資源未關閉造成的記憶體洩漏
對於使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等資源,應該在Activity銷燬時及時關閉或者登出,否則這些資源將不會被回收,從而造成記憶體洩漏。
6)使用ListView時造成的記憶體洩漏
初始時ListView會從BaseAdapter中根據當前的屏幕布局例項化一定數量的View物件,同時ListView會將這些View物件快取起來。當向上滾動ListView時,原先位於最上面的Item的View物件會被回收,然後被用來構造新出現在下面的Item。這個構造過程就是由getView()方法完成的,getView()的第二個形參convertView就是被快取起來的Item的View物件(初始化時快取中沒有View物件則convertView是null)。構造Adapter時,沒有使用快取的convertView。
7)集合容器中的記憶體洩露
我們通常把一些物件的引用加入到了集合容器(比如ArrayList)中,當我們不需要該物件時,並沒有把它的引用從集合中清理掉,這樣這個集合就會越來越大。如果這個集合是static的話,那情況就更嚴重了。
8)WebView造成的洩露
當我們不要使用WebView物件時,應該呼叫它的destory()函式來銷燬它,並釋放其佔用的記憶體,否則其長期佔用的記憶體也不能被回收,從而造成記憶體洩露。
如何防止記憶體洩漏?
1)在涉及使用Context時,對於生命週期比Activity長的物件應該使用Application的Context。凡是使用Context優先考慮Application的Context,當然它並不是萬能的,對於有些地方則必須使用Activity的Context。
2)對於需要在靜態內部類中使用非靜態外部成員變數(例如:Context、View
),可以在靜態內部類中使用弱引用來引用外部類的變數來避免記憶體洩漏。
3)對於不再需要使用的物件,顯示的將其賦值為null,比如使用完Bitmap後先呼叫recycle(),再賦為null。
4)保持對物件生命週期的敏感,特別注意單例、靜態物件、全域性性集合等的生命週期。
5)對於生命週期比Activity長的內部類物件,並且內部類中使用了外部類的成員變數,可以採用以下方式避免記憶體洩漏: ①
將內部類改為靜態內部類 ② 靜態內部類中使用弱引用來引用外部類的成員變數
記憶體洩漏和記憶體溢位區別?
記憶體洩漏:主要是因為程式存在BUG 導致記憶體沒有釋放 。 記憶體溢位:是指記憶體不夠用了,導致不夠用的原因很多,記憶體洩漏是導致記憶體溢位原因一種。
LruCache預設快取大小
LruCache預設快取大小是當前作業系統分配給該程序的記憶體的1/8。
廣播是否可以請求網路?
從4.0 開始所有的網路請求都需要線上程中,廣播請求網路同理 開啟執行緒線上程中請求網路
廣播引起anr的時間限制是多少?
Activity----->5秒
BroadcastReceiver----->10秒
Service----->20秒
Android為什麼引入Parcelable?
Java提供了Serializable介面方式實現序列化,但這種方式效率較低。因此,安卓提供Parcelable介面以實現更加高效的序列化方式。
簡述一下NDK
NDK(Native Development Kit)是Android的一個工具開發包。
NDK的目的是快速開發C、C++的動態庫,並自動將so和應用一起打包成APK。即可通過NDK在Android中使用JNI與原生代碼(如C、C++)互動。
JNI是什麼?
JNI是Java Native Interface的縮寫,它提供了若干的API實現了Java和其他語言的通訊(主要是C&C++)。
如何在jni中註冊native函式,有幾種註冊方式?
靜態註冊 動態註冊
JNI呼叫Java方法
JNI呼叫Java方法:首先通過類名找到類,然後根據方法名找到方法的id,然後呼叫該方法。
程序間通訊的方式?
安卓系統下程序間通訊主要有以下幾種方式:
1)Bundle
2)檔案共享
3)AIDL
4)Messager
5)ContentProvider
6)Socket
簡述AIDL?
AIDL是一個縮寫,全稱是Android Interface Definition Language,也就是Android介面定義語言,設計AIDL目的是為了實現程序間通訊,尤其是在涉及多程序併發情況下的程序間通訊。
Android程序分類?
1.前臺程序(foreground process):需要使用者當前正在進行的操作。一般滿足以下條件:
1)螢幕頂層執行Activity(處於onResume()狀態),使用者正與之互動 2)有BroadcastReceiver正在執行程式碼
3)有Service在其回撥方法(onCreate()、onStart()、onDestroy())中正在執行程式碼
這種程序較少,一般來作為最後的手段來回收記憶體
2.可視程序(visible process):做使用者當前意識到的工作。一般滿足以下條件:
1)螢幕上顯示Activity,但不可操作(處於onPause()狀態) 。
2)有service通過呼叫Service.startForeground(),作為一個前臺服務執行 。
3)含有使用者意識到的特定的服務,如動態桌布、輸入法等 。
這些程序很重要,一般不會殺死,除非這樣做可以使得所有前臺程序存活。
3.服務程序(service process):含有以startService()方法啟動的service。雖然該程序使用者不直接可見,但是它們一般做一些使用者關注的事情(如資料的上傳與下載)。
這些程序一般不會殺死,除非系統記憶體不足以保持前臺程序和可視程序的執行。對於長時間執行的service(如30分鐘以上),系統會考慮將之降級為快取程序,避免長時間執行導致記憶體洩漏或其他問題,佔用過多RAM以至於系統無法分配充足資源給快取程序。
4.快取/後臺程序(cached/background process):一般來說包含以下條件:
1)包含多個Activity例項,但是都不可見(處於onStop()且已返回)。 系統如有記憶體需要,可隨意殺死。
---------------------
附:安卓面試資料

面試資料
資料免費領取:
點贊+加群 4112676,驗證:面試題 即可