指南

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類:
    1. 在開始的記錄的點寫上代碼Debug.startMethodTracing("TAG");
    2. 在終止記錄的點寫上代碼Debug.stopMethodTracing();
    3. 通過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就會被一直引用,從而外部類也就一直被引用,導致內存泄漏。這種情況下建議:

    1. 使用靜態Handler
    2. 在退出時移除消息隊列中的消息
    3. 外部類引用使用弱引用處理
  • 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的繪制流程

  1. Measure過程:View的繪制其實就是一個深度遍歷的過程。這里有一個MeasureSpec的概念,每一個View都有一個MeasureSpec,它由父View根據自己的MeasureSpec和子View的LayoutParam共同決定。MeasureSpec有三個取值:
    1. MeasureSpec. UNSPECIFIED:不限制View大小
    2. MeasureSpec.EXACTLY:
    3. MeasureSpec.AT_MOST:
  2. Layout過程:
  3. Draw過程:
    1. Draw the background
    2. If necessary, save the canvas' layers to prepare for fading
    3. Draw view's content
    4. Draw children
    5. If necessary, draw the fading edges and restore layers
    6. Draw decorations (scrollbars for instance)

2. 說說Activity的啟動模式

啟動模式涉及到一個Task的概念,Task說的是為了完成一個任務的一系列的Activity的集合,這些Activity可以是來自不同的應用的。比如一個應用需要寫一封郵件,它用Intent去打開了郵件這個應用的寫郵件的MailActivity,這個Activity就可以和其它Activity同屬一個Task。

啟動模式有四種:

  1. standard
  2. singleTask
  3. singleTop
  4. singleInstance

標記位有三個:

  1. FLAG_ACTIVITY_NEW_TASK:
  2. FLAG_ACTIVITY_SINGLE_TOP:
  3. FLAG_ACTIVITY_CLEAR_TOP:

標記位優先級>啟動模式

3. 說說Activity的生命周期

  1. onCreate-->onStart()-->onResume()-->onPause()-->onStop()-->onDestrory()
    -->onRestart()
  2. 正常關閉情況下onSaveInstanceState() 以及 onRestoreInstanceState()這兩個方法是不會被調用的。它們只會在Activity不正常關閉下調用。我們說的視圖恢復就是指的不正常關閉時候,Activity再次打開的時候要讓用戶感覺到Activity并沒有被關閉。
  3. 建議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的過程。主要有三個大的方法參與這個過程:

  1. dispatchTouchEvent()
  2. onInterceptTouchEvent() (ViewGroup獨有)
  3. onTouchEvent()

其中dispatchTouchEvent負責尋找到一個新的TouchTarget,,并把事件交給TouchTarget。onInterceptTouchEvent()指示當前ViewGroup是否攔截此次事件。onTouchEvent()處理事件,它的返回代表當前事件是否被這個View消耗。

onTouch()--> onTouchEvent()-->onClick()

5. 內存泄漏

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容