啟動Activity的幾種方法有什么區(qū)別?
- standard
創(chuàng)建新對象 - singleInstance
只有一個實(shí)例 - singleTask
新建一個棧 - singleTop
如果在頂端就不創(chuàng)建直接用,否則創(chuàng)建。
講解你的項(xiàng)目架構(gòu)
常用的設(shè)計(jì)模式
代理和動態(tài)代理
1.靜態(tài)代理
2.動態(tài)代理
實(shí)現(xiàn) InvocationHandler
bind/invoke
AOP編程: Spring MVC,Structs的攔截器
觀察者模式
Adapter模式
仲裁模式
單例(線程安全)
- 線程安全單例
- 1.饑餓式
- 2.懶漢式
- 3.靜態(tài)成員類
- 4.枚舉
- 內(nèi)存泄漏問題
單例傳入Context會引起內(nèi)存泄漏,無法釋放,改成傳入ApplicationContext
或者參數(shù)不要持有,僅僅在單例的方法中參入,而不是構(gòu)造函數(shù)中傳入。
簡單工廠有什么特點(diǎn)?
Android多設(shè)備UI適配
- dp/sp
- 百分比
Android熱更新原理
Android內(nèi)存泄漏
內(nèi)存泄漏
如果一個不需要再使用的對象(強(qiáng)引用)仍然被其他對象持有引用,造成該對象無法被系統(tǒng)回收。
1.什么情況下會造成內(nèi)存泄漏?
單例導(dǎo)致內(nèi)存泄漏
靜態(tài)變量導(dǎo)致內(nèi)存泄漏
-
非靜態(tài)內(nèi)部類導(dǎo)致內(nèi)存泄漏
- Handler/Thread/AsyncTask
靜態(tài)內(nèi)部類+弱引用
mHandler.removeCallbacksAndMessages(null); 緩存沒有釋放不再引用的對象
未取消注冊或回調(diào)導(dǎo)致內(nèi)存泄露
-
Timer和TimerTask導(dǎo)致內(nèi)存泄露
cancel timer
集合中的對象未清理造成內(nèi)存泄露
資源未關(guān)閉或釋放導(dǎo)致內(nèi)存泄露
屬性動畫造成內(nèi)存泄露
WebView造成內(nèi)存泄露
2.如何調(diào)試分析?
- WeTest 騰訊
- in
- Android MAT
- LeakCanary Square
Android Lint
- 靜態(tài)代碼檢查
- 靜態(tài)代碼檢查框架
- Lint的優(yōu)點(diǎn)
- 功能強(qiáng)大,Lint支持Java源文件、class文件、資源文件、Gradle等文件的檢查。
- 擴(kuò)展性強(qiáng),支持開發(fā)自定義Lint規(guī)則。
- 配套工具完善,Android Studio、Android Gradle插件原生支持Lint工具。
- Lint專為Android設(shè)計(jì),原生提供了幾百個實(shí)用的Android相關(guān)檢查規(guī)則。
- 有Google官方的支持,會和Android開發(fā)工具一起升級完善。
- 參考 美圖技術(shù)文章
Activity傳遞大數(shù)據(jù)怎么辦?
- Bundle最大約1M
TransactionTooLargeException
The Binder transaction failed because it was too large - 傳遞大數(shù)據(jù)(比如bitmap)盡量避免采用bundle傳遞
- 寫文件或數(shù)據(jù)庫
- 寫全局緩存(需要和調(diào)用者在一個進(jìn)程)
- 單例(需要和調(diào)用者在一個進(jìn)程)
Service和IntentService的區(qū)別
1.Service
Service 是長期運(yùn)行在后臺的應(yīng)用程序組件。
Service 不是一個單獨(dú)的進(jìn)程,它和應(yīng)用程序在同一個進(jìn)程中,Service 也不是一個線程,它和線程沒有任何關(guān)系,所以它不能直接處理耗時操作。如果直接把耗時操作放在 Service 的 onStartCommand() 中,很容易引起 ANR .如果有耗時操作就必須開啟一個單獨(dú)的線程來處理。
2.IntentService
IntentService 是繼承于 Service 并處理異步請求的一個類,在 IntentService 內(nèi)有一個工作線程來處理耗時操作,啟動 IntentService 的方式和啟動傳統(tǒng) Service 一樣,同時,當(dāng)任務(wù)執(zhí)行完后,IntentService 會自動停止,而不需要我們?nèi)ナ謩涌刂?。另外,可以啟?IntentService 多次,而每一個耗時操作會以工作隊(duì)列的方式在IntentService 的 onHandleIntent 回調(diào)方法中執(zhí)行,并且,每次只會執(zhí)行一個工作線程,執(zhí)行完第一個再執(zhí)行第二個,以此類推。
而且,所有請求都在一個單線程中,不會阻塞應(yīng)用程序的主線程(UI Thread),同一時間只處理一個請求。
IntentService是一個通過Context.startService(Intent)啟動可以處理異步請求的Service,使用時你只需要繼承IntentService和重寫其中的onHandleIntent(Intent)方法接收一個Intent對象,在適當(dāng)?shù)臅r候會停止自己(一般在工作完成的時候). 所有的請求的處理都在一個工作線程中完成,它們會交替執(zhí)行(但不會阻塞主線程的執(zhí)行),一次只能執(zhí)行一個請求。
這是一個基于消息的服務(wù),每次啟動該服務(wù)并不是馬上處理你的工作,而是首先會創(chuàng)建對應(yīng)的Looper,Handler并且在MessageQueue中添加的附帶客戶Intent的Message對象,當(dāng)Looper發(fā)現(xiàn)有Message的時候接著得到Intent對象通過在onHandleIntent((Intent)msg.obj)中調(diào)用你的處理程序.處理完后即會停止自己的服務(wù).意思是Intent的生命周期跟你的處理的任務(wù)是一致的.所以這個類用下載任務(wù)中非常好,下載任務(wù)結(jié)束后服務(wù)自身就會結(jié)束退出.
應(yīng)用內(nèi)廣播
LocalBroadcastManager
避免廣播敏感信息,被其他惡意的receiver接收到.
Handler一定要在主線程實(shí)例化嗎?new Handler()和new Handler(Looper.getMainLooper())的區(qū)別
| 場景 | 當(dāng)前在主線程 | 當(dāng)前在工作線程 |
|---|---|---|
| 需要刷新UI | Handler handler = new Handler(); | Handler handler = new Handler(Looper.getMainLooper()); |
| 不用刷新ui,只是處理消息 | Handler handler = new Handler(); | Looper.prepare(); Handler handler = new Handler();Looper.loop();或Handler handler = new Handler(Looper.getMainLooper()); |
1. Handler handler = new Handler();默認(rèn)使用當(dāng)前線程的looper
2. 如果需要刷新UI,那么1的代碼需要在主線程創(chuàng)建。如果不是在主線程可以通過傳入?yún)?shù)指定主線程的looper。
Handler handler = new Handler(Looper.getMainLooper());
3.不用刷新ui,只是處理消息。 當(dāng)前線程如果是主線程的話,Handler handler = new Handler();不是主線程的話,Looper.prepare(); Handler handler = new Handler();Looper.loop();或者Handler handler = new Handler(Looper.getMainLooper());
HandlerThread的特點(diǎn)
HandlerThread將loop轉(zhuǎn)到子線程中處理,說白了就是將分擔(dān)MainLooper的工作量,降低了主線程的壓力,使主界面更流暢。
開啟一個線程起到多個線程的作用。處理任務(wù)是串行執(zhí)行,按消息發(fā)送順序進(jìn)行處理。HandlerThread本質(zhì)是一個線程,在線程內(nèi)部,代碼是串行處理的。
但是由于每一個任務(wù)都將以隊(duì)列的方式逐個被執(zhí)行到,一旦隊(duì)列中有某個任務(wù)執(zhí)行時間過長,那么就會導(dǎo)致后續(xù)的任務(wù)都會被延遲處理。
HandlerThread擁有自己的消息隊(duì)列,它不會干擾或阻塞UI線程。
對于網(wǎng)絡(luò)IO操作,HandlerThread并不適合,因?yàn)樗挥幸粋€線程,還得排隊(duì)一個一個等著。
Android架構(gòu)設(shè)計(jì)
- Android Architecture Components
- 反編譯其他APP來學(xué)習(xí)
- 根據(jù)APP業(yè)務(wù)特點(diǎn)來確定架構(gòu)
- 分層設(shè)計(jì)
- UI (Activity/Fragment/Views
UI相關(guān)
1.不能使用 ScrollView 包裹 ListView/GridView/ExpandableListVIew
因?yàn)檫@ 樣會把 ListView 的所有 Item 都加載到內(nèi)存中,要消耗巨大的內(nèi)存和 cpu 去繪制圖面。
推薦使用 NestedScrollView。
Android更新UI的幾種方法
1.Handler+View.invalidate+Thread+Runnable
2.View.postInvalidate+Thread+Runnable
postInvalidate就是把message(MSG_INVALIDATE,view)丟給主線程mHandler,mHandler收到后view.invalidate
3.Handler+Worker Thread
自定義主線程Handler,從Worker Thread發(fā)送消息
4.Worker Thread 中runOnUiThread
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);//將Runnable Post到消息隊(duì)列,由內(nèi)部的mHandler來處理,實(shí)際上也是Handler的處理方式
} else {
action.run();//已經(jīng)在UI線程,直接運(yùn)行。
}
}