安卓面試題 進階篇

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()且已返回)。 系統如有內存需要,可隨意殺死。

喜歡的話請幫忙轉發一下能讓更多有需要的人看到吧,有些技術上的問題大家可以多探討一下。

更多面試資料或其他Android資料可在QQ羣裏獲取:936903570。有加羣的朋友請記得備註上CSDN,謝謝。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章