Activity
Service
Broadcast
ContentProvider
Fragment
View
View繪制
View事件分發
自定義View
View滑動
控件
RecyclerView
ListView
ViewPager
動畫
Bitmap && Drawable
Android線程與進程
Handler/Looper
Binder
序列化
進程保活
AsyncTask
HandlerThread
IntentService
IPC
線程池
Android優化
ANR
1. ANR是什么?如何避免和解決ANR?
ANR:Application Not Responding,即應用無響應。一般有以下三種:
- KeyDispatchTimeout:5s
- BroadcatTimeout:10s
- ServiceTimeout:20s
造成Timeout的原因一般有兩種:
主線程阻塞在了某個消息中
當前事件正在被處理但是沒有被處理完
操作阻塞的原因可能是:
- 耗時的網絡操作
- 大量的數據讀寫
- 數據庫操作
- 硬件操作
- 線程等待
- 發生了死鎖
- 動畫耗時
- Cpu負載高
問題定位:
- ANR產生時,系統會生成一個tarces.txt的文本文件放在/data/anr下,最新的ANR信息在最開始的位置。通過ADB命令
adb pull data/anr/traces.txt .
可以導出到本地分析。 - 使用Android Studio中的Profile工具可以方便的得到每個方法的運行時間
- 使用Android SDK中提供的Debug類:
- 在開始的記錄的點寫上代碼Debug.startMethodTracing("TAG");
- 在終止記錄的點寫上代碼Debug.stopMethodTracing();
- 通過adb pull /data/tracePath.trace導出文件并使用Android Studio打開分析
解決方法:
- 不要在主線程中去做耗時操作,將耗時操作放在子線程中去。通過Thread、HandlerThread、IntentService、AsyncTask
- 同樣由于Service/Broadcast運行在主線程,Service中也不能做耗時操作
- 在使用Thread或者HandlerThread時,可以嘗試調用Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)設置較低優先級,否則依然會降低程序響應,因為默認Thread的優先級和主線程相同。
- 任何UI線程中的方法都應該簡短快捷,類似調整Bitmap大小這種需要長時間計算的操作,都應該執行在工作線程中。
- BroadcastReceiver中的onReceive()方法如果必須執行耗時操作,建議在這個方法中開啟IntentService來執行耗時操作。
內存泄漏memory leak
1. 內存泄漏的原因、場景、解決方法?
根本原因:長生命周期的對象持有短生命周期的對象,導致短生命周期對象就無法及時釋放。
泄漏場景:
非靜態內部類的靜態實例
非靜態內部類會持有外部類的引用,如果這個非靜態內部類的實例恰好是個靜態實例,那么這個實例就會長時間的存在,從而導致外部類長時間被引用,就無法被回收,從而造成外部類的內存泄漏。匿名內部類
匿名內部類同樣會持有外部類的引用,如果這個匿名內部類中做了耗時操作,就會導致外部類長時間被引用從而無法回收。-
Handler內存泄漏
Handler內存泄漏也可以歸納為非靜態內部類導致的,Handler發送的消息Message首先會將自己的target指向當前Handler對象,然后這個Message會被加入到Looper中的MessageQueue中等待被處理。如果消息長時間得不到處理,Handler就會被一直引用,從而外部類也就一直被引用,導致內存泄漏。這種情況下建議:
- 使用靜態Handler
- 在退出時移除消息隊列中的消息
- 外部類引用使用弱引用處理
Context內存泄漏
根據場景確定使用Activity的Context還是ApplicationContext,因為兩者生命周期不同,對于不必須使用Activity的Context的場景(Dialog),一律采用ApplicationContext。單例模式是最常見的發生此泄漏的場景。比如傳入一個Activity的Context被靜態類引用,導致無法回收。-
靜態View內存泄漏
使用靜態View可以避免每次啟動Activity都去讀取并渲染View,但是View會持有Activity的引用,導致無法回收。解決辦法時在Activity銷毀的時候將靜態View設置為null(View一旦被加載到界面上會持有一個Context對象的引用,這里就是Activity。)
WebView導致的內存泄漏
WebView只要使用一次,內存就不會被釋放,所以WebView都存在內存泄漏的問題。通常的解決辦法時為WebView單獨打開一個進程,使用AIDL進行通信,根據業務需求在合適的時機釋放掉。資源對象未關閉
集合中的對象未清理
-
Bitmap內存泄漏
避免靜態變量持有大的Bitmap對象。
監聽器未關閉
很多需要register和unregister的系統服務要在合適的時候進行unregister,手動添加的listener也要及時移除。
檢測方法:
- LeakCanary
OOM (out of memory)
冷啟動&&熱啟動
性能優化
UI優化
其它
Context
1. 談談你對Android中Context的理解?
Context:包含上下文信息的一個參數。Android 中的 Context 分三種:
Application Context
Activity Context
Service Context
它描述的是一個應用程序環境的信息, 通過它我們可以獲取應用程序的資源和類,也包括一些應用級別操作, 例如: 啟動一個 Activity, 發送廣播, 接受 Intent 信息等。
Application
權限
Android中的強、弱、軟、虛應用
LruCache && DiskLruCache
第三方庫
OkHttp
Glide
1. 說說View的繪制流程
- Measure過程:View的繪制其實就是一個深度遍歷的過程。這里有一個MeasureSpec的概念,每一個View都有一個MeasureSpec,它由父View根據自己的MeasureSpec和子View的LayoutParam共同決定。MeasureSpec有三個取值:
- MeasureSpec. UNSPECIFIED:不限制View大小
- MeasureSpec.EXACTLY:
- MeasureSpec.AT_MOST:
- Layout過程:
- Draw過程:
- Draw the background
- If necessary, save the canvas' layers to prepare for fading
- Draw view's content
- Draw children
- If necessary, draw the fading edges and restore layers
- Draw decorations (scrollbars for instance)
2. 說說Activity的啟動模式
啟動模式涉及到一個Task的概念,Task說的是為了完成一個任務的一系列的Activity的集合,這些Activity可以是來自不同的應用的。比如一個應用需要寫一封郵件,它用Intent去打開了郵件這個應用的寫郵件的MailActivity,這個Activity就可以和其它Activity同屬一個Task。
啟動模式有四種:
- standard:
- singleTask:
- singleTop:
- singleInstance:
標記位有三個:
- FLAG_ACTIVITY_NEW_TASK:
- FLAG_ACTIVITY_SINGLE_TOP:
- FLAG_ACTIVITY_CLEAR_TOP:
標記位優先級>啟動模式
3. 說說Activity的生命周期
- onCreate-->onStart()-->onResume()-->onPause()-->onStop()-->onDestrory()
-->onRestart() - 正常關閉情況下onSaveInstanceState() 以及 onRestoreInstanceState()這兩個方法是不會被調用的。它們只會在Activity不正常關閉下調用。我們說的視圖恢復就是指的不正常關閉時候,Activity再次打開的時候要讓用戶感覺到Activity并沒有被關閉。
- 建議onStop()中保存數據
4. 說說View事件分發
手指在屏幕的動作被抽象成了MotionEvent對象,根據不同情境分成了MotionEvent.ACTION_DOWN、MotionEvent.ACTION_POINTER_DOWN、MotionEvent.ACTION_MOVE、MotionEvent.ACTION_UP、MotionEvent.ACTON_CANCLE。事件分發主要就是當ACTION_DOWN以及ACTION_POINTER_DOWN兩個事件到來時尋找新的TouchTarget的過程。主要有三個大的方法參與這個過程:
- dispatchTouchEvent()
- onInterceptTouchEvent() (ViewGroup獨有)
- onTouchEvent()
其中dispatchTouchEvent負責尋找到一個新的TouchTarget,,并把事件交給TouchTarget。onInterceptTouchEvent()指示當前ViewGroup是否攔截此次事件。onTouchEvent()處理事件,它的返回代表當前事件是否被這個View消耗。
onTouch()--> onTouchEvent()-->onClick()