1. 程式人生 > >Activity 的 36 大難點,你會幾個?「建議收藏」

Activity 的 36 大難點,你會幾個?「建議收藏」

前言

Android 有一段時間了,一直都只顧著學新的東西,最近發現很多平常用的少的東西竟讓都忘了,趁著這兩天,打算把有關 Activity 的內容以問題的形式梳理出來,也供大家查缺補漏。

本文中,我將一改往日寫部落格的習慣,全文用 XMind 將所有知識點以思維導圖的形式呈現,歡迎大家食用~~

# 文章目錄

方便大家學習,我在 GitHub 上建立個 倉庫


  • 倉庫內容與部落格同步更新。由於我在 稀土掘金 簡書 CSDN 部落格園 等站點,都有新內容釋出。所以大家可以直接關注該倉庫,以免錯過精彩內容!

  • 倉庫地址:
    超級乾貨!精心歸納 AndroidJVM 、演算法等,各位帥氣的老鐵支援一下!給個 Star !

# 神圖

  • 在開始之前,先讓我們看看 Androidactivity 到底都有哪些東西?
  • 借一張網上很火的圖帶你瞭解 Activity

# 1. 生命週期

  • 先貼一張聞名遐邇的圖
  • 我們生命週期先看看具體有哪些方法回撥,在逐一攻破:

1.1 Dialog 彈出時

  • 如果是單純是建立的 dialogActivity 並不會執行生命週期的方法
  • 但是如果是跳轉到一個不是全屏的 Activity 的話, 當然就是按照正常的生命週期來執行了
  • onPasue() -> onStop()

1.2 橫豎屏切換時

  • 不設定 Activityandroid:configChanges
    時,切屏會重新呼叫各個生命週期,切橫屏時會執行一次,切豎屏時會執行兩次
  • 設定 Activityandroid:configChanges="orientation" 時,切屏還是會重新呼叫各個生命週期,切橫、豎屏時只會執行一次
  • 設定 Activityandroid:configChanges="orientation|keyboardHidden" 時,切屏不會重新呼叫各個生命週期,只會執行 onConfigurationChanged 方法
  • 注意:還有一點,非常重要,一個 Android 的變更細節!當 API >12 時,需要加入 screenSize
    屬性,否則螢幕切換時即使你設定了 orientation 系統也會重建 Activity

橫豎屏切換生命週期的執行

1.3 不同場景下 Activity 生命週期的變化過程

  • 啟動 ActivityonCreate() ---> onStart() ---> onResume()Activity 進入執行狀態。
  • 鎖屏時會執行 onPause()onStop() , 而開屏時則應該執行 onStart() onResume()

  • Activity 退居後臺: 當前 Activity 轉到新的 Activity 介面或按 Home 鍵回到主屏: onPause() ---> onStop() ,進入停滯狀態。
  • Activity 返回前臺: onRestart() ---> onStart() ---> onResume() ,再次回到執行狀態。
  • Activity 退居後臺: 且系統記憶體不足, 系統會殺死這個後臺狀態的 Activity ,若再次回到這個 Activity ,則會走 onCreate() --> onStart() ---> onResume()

1.4 將一個 Activity 設定成視窗的樣式

只需要給我們的 Activity 配置如下屬性即可。
android:theme="@android:style/Theme.Dialog"

1.5 退出已呼叫多個 Activity 的 Application

  • 通常情況使用者退出一個 Activity 只需按返回鍵,我們寫程式碼想退出 activity 直接呼叫 finish() 方法就行。

  • 傳送特定廣播:
  1. 在需要結束應用時, 傳送一個特定的廣播,每個 Activity 收到廣播後,關閉 即可。
  2. 給某個 activity 註冊接受接受廣播的意圖 registerReceiver(receiver, filter)
  3. 如果過接受到的是 關閉 activity 的廣播 activity finish()
  • 遞迴退出
  1. 就呼叫 finish() 方法 把當前的 Activity 退出
  2. 在開啟新的 Activity 時使用 startActivityForResult , 然後自己加標誌, 在 onActivityResult 中處理, 遞迴關閉。
  • 其實
  1. 也可以通過 intentflag 來實現 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) 啟用一個新的 activity
  2. 此時如果該任務棧中已經有該 Activity , 那麼系統會把這個 Activity 上面的所有 Activity 幹掉。
  3. 其實相當於給 Activity 配置的啟動模式為 SingleTop
  • 記錄開啟的 Activity
  1. 每開啟一個 Activity , 就記錄下來。
  2. 在需要退出時 , 關閉每一個 Activity

1.6 鎖定屏與解鎖螢幕,Activity 如何執行生命週期

  • 鎖屏時會執行 onPause()onStop() , 而開屏時則應該執行 onStart() onResume()

1.7 修改 Activity 進入和退出動畫

  • 可以通過兩種方式 , 一是通過定義 Activity 的主題 ,二是通過覆寫 ActivityoverridePendingTransition 方法。
  • 通過設定主題樣式在 styles.xml 中編輯程式碼 , 新增 themes.xml 檔案:在 AndroidManifest.xml 中給指定的 Activity 指定 theme
  • 覆寫 overridePendingTransition 方法:overridePendingTransition(R.anim.fade, R.anim.hold);

1.8 Activity 的四種狀態

  • runnig :使用者可以點選,activity 處於棧頂狀態。
  • pausedactivity 失去焦點的時候,被一個非全屏的 activity 佔據或者被一個透明的 activity 覆蓋,這個狀態的 activity 並沒有銷燬,它所有的狀態資訊和成員變數仍然存在,只是不能夠被點選。(記憶體緊張的情況,這個 activity 有可能被回收)

  • stopped :這個 activity 被另外一個 activity 完全覆蓋,但是這個 activity 的所有狀態資訊和成員變數仍然存在(除了記憶體緊張)
  • killed :這個 activity 已經被銷燬,其所有的狀態資訊和成員變數已經不存在了。

1.9 如何處理異常退出

  • Activity 異常退出的時候 --> onPause() --> onSaveInstanceState() --> onStop() --> onDestory()
  • 需要注意的是 onSaveInstanceState() 方法與 onPause 並沒有嚴格的先後關係,有可能在 onPause 之前,也有可能在其後面呼叫,但會在 onStop() 方法之前呼叫
  • 異常退出後又重新啟動該 Activity --> onCreate() --> onStart() --> onRestoreInstanceState() --> onResume()

  • 搞懂這個生命週期的執行後就可以回答了,首先要知道面試官的意思:是要重新啟動並恢復這個 Activity 還是說直接退出整個 app
  • 如果要恢復則要在 onSaveInstanceState() 中進行儲存資料並在 onRestoreInstanceState() 中進行恢復
  • 如果是要退出 app 的話就要捕獲全域性的異常資訊,並退出 app
  • 當然個人建議是使用 UncaughtExceotionHandler 來捕獲全域性異常進行退出 app 的操作,這樣會減少之前崩潰所造成的後遺症!

1.10 什麼是 onNewIntent

  • 如果 IntentActivity 處於任務棧的頂端,也就是說之前開啟過的 Activity ,現在處於 onPauseonStop 狀態的話,其他應用再發送 Intent 的話

  • 執行順序為:onNewIntentonRestartonStartonResume

2. 啟動模式


2.1 啟動模式

  • Activity 一共有四種 launchModestandardsingleTopsingleTasksingleInstance

  • Standard 模式(預設模式)
  1. 說明: 每次啟動一個 Activity 都會又一次建立一個新的例項入棧,無論這個例項是否存在。

  2. 生命週期:每次被建立的例項 Activity 的生命週期符合典型情況,它的 onCreateonStartonResume 都會被呼叫。

  3. 舉例:此時 Activity 棧中以此有 ABC 三個 Activity ,此時C處於棧頂,啟動模式為 Standard 模式。若在 C Activity 中加入點選事件,須要跳轉到還有一個同類型的 C Activity 。結果是還有一個 C Activity 進入棧中,成為棧頂。

  • SingleTop 模式(棧頂複用模式)
  1. 說明:分兩種處理情況:須要建立的 Activity 已經處於棧頂時,此時會直接複用棧頂的 Activity 。不會再建立新的 Activity ;若須要建立的 Activity 不處於棧頂,此時會又一次建立一個新的 Activity 入棧,同 Standard 模式一樣。

  2. 生命週期:若情況一中棧頂的 Activity 被直接複用時,它的 onCreateonStart 不會被系統呼叫,由於它並沒有發生改變。可是一個新的方法 onNewIntent 會被回撥( Activity 被正常建立時不會回撥此方法)。

  3. 舉例:此時 Activity 棧中以此有 ABC 三個 Activity ,此時 C 處於棧頂,啟動模式為 SingleTop 模式。情況一:在 C Activity 中加入點選事件,須要跳轉到還有一個同類型的 C Activity 。結果是直接複用棧頂的 C Activity。情況二:在 C Activity 中加入點選事件,須要跳轉到還有一個 A Activity。結果是建立一個新的 Activity 入棧。成為棧頂。

  • SingleTask 模式(棧內複用模式)
  1. 說明:若須要建立的 Activity 已經處於棧中時,此時不會建立新的 Activity ,而是將存在棧中的 Activity 上面的其他 Activity 所有銷燬,使它成為棧頂。

  2. 如果是在別的應用程式中啟動它,則會新建一個 task ,並在該task中啟動這個 ActivitysingleTask 允許別的 Activity 與其在一個 task 中共存,也就是說,如果我在這個 singleTask 的例項中再開啟新的 Activity ,這個新的 Activity 還是會在 singleTask 的例項的 task 中。

  3. 生命週期:同 SingleTop 模式中的情況一同樣。僅僅會又一次回撥 Activity 中的 onNewIntent 方法

  4. 舉例:此時 Activity 棧中以此有 ABC 三個 Activity 。此時 C 處於棧頂,啟動模式為 SingleTask 模式。情況一:在 C Activity 中加入點選事件,須要跳轉到還有一個同類型的 C Activity 。結果是直接用棧頂的 C Activity 。情況二:在 C Activity 中加入點選事件,須要跳轉到還有一個 A Activity 。結果是將 A Activity 上面的 BC 所有銷燬,使 A Activity 成為棧頂。

  • SingleInstance 模式(單例項模式)
  1. 說明: SingleInstance 比較特殊,是全域性單例模式,是一種加強的 SingleTask 模式。它除了具有它所有特性外,還加強了一點:只有一個例項,並且這個例項獨立執行在一個 task 中,這個 task 只有這個例項,不允許有別的 Activity 存在。

  2. 這個經常使用於系統中的應用,比如 Launch 、鎖屏鍵的應用等等,整個系統中僅僅有一個!所以在我們的應用中一般不會用到。瞭解就可以。

  3. 舉例:比方 A Activity 是該模式,啟動 A 後。系統會為它建立一個單獨的任務棧,由於棧內複用的特性。興許的請求均不會建立新的 Activity ,除非這個獨特的任務棧被系統銷燬。

2.2 啟動模式的使用方式

  • Manifest.xml 中指定 Activity 啟動模式
  1. 一種靜態的指定方法
  2. Manifest.xml 檔案裡宣告 Activity 的同一時候指定它的啟動模式
  3. 這樣在程式碼中跳轉時會依照指定的模式來建立 Activity
  • 啟動 Activity 時。在 Intent 中指定啟動模式去建立 Activity
  1. 一種動態的啟動模式
  2. new 一個 Intent
  3. 通過 IntentaddFlags 方法去動態指定一個啟動模式。
  • 注意:以上兩種方式都能夠為 Activity 指定啟動模式,可是二者還是有差別的。
  1. 優先順序:動態指定方式即另外一種比第一種優先順序要高,若兩者同一時候存在,以另外一種方式為準。

  2. 限定範圍:第一種方式無法為 Activity 直接指定 FLAG_ACTIVITY_CLEAR_TOP 標識,另外一種方式無法為 Activity 指定 singleInstance 模式。

2.3 啟動模式的實際應用場景

這四種模式中的 Standard 模式是最普通的一種,沒有什麼特別注意。而 SingleInstance 模式是整個系統的單例模式,在我們的應用中一般不會應用到。所以,這裡就具體解說 SingleTopSingleTask 模式的運用場景:

  • SingleTask 模式的運用場景
  1. 最常見的應用場景就是保持我們應用開啟後僅僅有一個 Activity 的例項。
  2. 最典型的樣例就是應用中展示的主頁( Home 頁)。
  3. 假設使用者在主頁跳轉到其他頁面,執行多次操作後想返回到主頁,假設不使用 SingleTask 模式,在點選返回的過程中會多次看到主頁,這明顯就是設計不合理了。
  • SingleTop 模式的運用場景
  1. 假設你在當前的 Activity 中又要啟動同類型的 Activity
  2. 此時建議將此型別 Activity 的啟動模式指定為 SingleTop ,能夠降低Activity的建立,節省記憶體!
  • 注意:複用 Activity 時的生命週期回撥
  1. 這裡還須要考慮一個 Activity 跳轉時攜帶頁面引數的問題。
  2. 由於當一個 Activity 設定了 SingleTop 或者 SingleTask 模式後,跳轉此 Activity 出現複用原有 Activity 的情況時,此 ActivityonCreate 方法將不會再次執行。onCreate 方法僅僅會在第一次建立 Activity 時被執行。
  3. 而一般 onCreate 方法中會進行該頁面的資料初始化、UI 初始化,假設頁面的展示資料無關頁面跳轉傳遞的引數,則不必操心此問題
  4. 若頁面展示的資料就是通過 getInten() 方法來獲取,那麼問題就會出現:getInten() 獲取的一直都是老資料,根本無法接收跳轉時傳送的新資料!
  • 以下,通過一個樣例來具體解釋:

  • 以上程式碼中的 CourseDetailActivity 在配置檔案裡設定了啟動模式是 SingleTop 模式,依據上面啟動模式的介紹可得知,當 CourseDetailActivity 處於棧頂時。
  • 再次跳轉頁面到 CourseDetailActivity 時會直接複用原有的 Activity ,並且此頁面須要展示的資料是從 getIntent() 方法得來,可是 initData() 方法不會再次被呼叫,此時頁面就無法顯示新的資料。

  • 當然這樣的情況系統早就為我們想過了,這時我們須要另外一個回撥 onNewIntent(Intent intent)方法。此方法會傳入最新的 intent ,這樣我們就能夠解決上述問題。這裡建議的方法是又一次去 setIntent 。然後又一次去初始化資料和 UI 。程式碼例如以下所看到的:

  • 這樣,在一個頁面中能夠反覆跳轉並顯示不同的內容。

2.4 快速啟動一個 Activity

  • 這個問題其實也是比較簡單的,就是不要在 ActivityonCreate 方法中執行過多繁重的操作,並且在 onPasue 方法中同樣不能做過多的耗時操作。

2.5 啟動流程

  • 注意!這裡並不是要回答 Activity 的生命週期!

  • 3 分鐘看懂 Activity 啟動流程

2.6 Activity 的 Flags

  • 標記位既能夠設定Activity的啟動模式,如同上面介紹的,在動態指定啟動模式,比方 FLAG_ACTIVITY_NEW_TASKFLAG_ACTIVITY_SINGLE_TOP 等。它還能夠影響 Activity 的執行狀態 ,比方 FLAG_ACTIVITY_CLEAN_TOPFLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 等。

  • 以下介紹幾個基本的標記位,切勿死記,理解幾個就可以,須要時再查官方文件。

  • FLAG_ACTIVITY_NEW_TASK
  1. 作用是為 Activity 指定 “SingleTask” 啟動模式。跟在 AndroidMainfest.xml 指定效果同樣
  • FLAG_ACTIVITY_SINGLE_TOP
  1. 作用是為 Activity 指定 “SingleTop” 啟動模式,跟在 AndroidMainfest.xml 指定效果同樣。
  • FLAG_ACTIVITY_CLEAN_TOP
  1. 具有此標記位的 Activity ,啟動時會將與該 Activity 在同一任務棧的其他 Activity 出棧。
  2. 一般與 SingleTask 啟動模式一起出現。
  3. 它會完畢 SingleTask 的作用。
  4. 但事實上 SingleTask 啟動模式預設具有此標記位的作用
  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
  1. 具有此標記位的 Activity 不會出如今歷史 Activity 的列表中
  2. 使用場景:當某些情況下我們不希望使用者通過歷史列表回到 Activity 時,此標記位便體現了它的效果。
  3. 它等同於在 xml 中指定 Activity 的屬性.

2.7 onNewInstent()方法什麼時候執行

這個是啟動模式中的了,當此 Activity 的例項已經存在,並且此時的啟動模式為 SingleTaskSingleInstance ,另外當這個例項位於棧頂且啟動模式為 SingleTop 時也會觸發 onNewInstent()

# 3. 資料

3.1 Activity 間通過 Intent 傳遞資料大小限制

  • Intent 在傳遞資料時是有大小限制的,這裡官方並未詳細說明,不過通過實驗的方法可以測出資料應該被限制在 1MB 之內( 1024KB
  • 我們採用傳遞 Bitmap 的方法,發現當圖片大小超過 1024(準確地說是 1020 左右)的時候,程式就會出現閃退、停止執行等異常(不同的手機反應不同)
  • 因此可以判斷 Intent 的傳輸容量在 1MB 之內。

3.2 記憶體不足時系統會殺掉後臺的Activity,若需要進行一些臨時狀態的儲存,在哪個方法進行

  • ActivityonSaveInstanceState()onRestoreInstanceState() 並不是生命週期方法,它們不同於 onCreate()onPause() 等生命週期方法,它們並不一定會被觸發。

  • onSaveInstanceState() 方法,當應用遇到意外情況(如:記憶體不足、使用者直接按 Home 鍵)由系統銷燬一個 ActivityonSaveInstanceState() 會被呼叫。
  • 但是當用戶主動去銷燬一個 Activity 時,例如在應用中按返回鍵,onSaveInstanceState() 就不會被呼叫。
  • 除非該 activity 不是被使用者主動銷燬的,通常 onSaveInstanceState() 只適合用於儲存一些臨時性的狀態,而 onPause() 適合用於資料的持久化儲存。

3.3 onSaveInstanceState() 被執行的場景

  • 系統不知道你按下 HOME 後要執行多少其他的程式,自然也不知道 activity A 是否會被銷燬
  • 因此係統都會呼叫 onSaveInstanceState() ,讓使用者有機會儲存某些非永久性的資料。以下幾種情況的分析都遵循該原則:
  1. 當用戶按下 HOME 鍵時
  2. 長按 HOME 鍵,選擇執行其他的程式時
  3. 鎖屏時
  4. activity A 中啟動一個新的 activity
  5. 螢幕方向切換時

3.4 兩個 Activity 之間跳轉時必然會執行的方法

一般情況下比如說有兩個 activity , 分別叫 A , B ,當在 A 裡面啟用 B 元件的時候, A 會呼叫 onPause() 方法,然後 B 呼叫 onCreate() , onStart() , onResume()

這個時候 B 覆蓋了窗體, A 會呼叫 onStop() 方法. 如果 B 是個透明的,或者 是對話方塊的樣式, 就不會呼叫 AonStop() 方法。

3.5 用 Intent 去啟動一個Activity 之外的方法

  • 使用 adb shell am 命令
  1. am 啟動一個 activity
  2. adb shell am start com.example.fuchenxuan/.MainActivity
  3. am 傳送一個廣播,使用 action
  4. adb shell am broadcast -a magcomm.action.TOUCH_LETTER

3.6 scheme 跳轉協議

3.6.1 定義

  • 伺服器可以定製化跳轉 app 頁面

  • app 可以通過 Scheme 跳轉到另一個 app 頁面

  • 可以通過 h5 頁面跳轉 app 原生頁面

3.6.2 協議格式:

  • qh 代表 Scheme 協議名稱

  • test 代表 Scheme 作用的地址域

  • 8080 代表改路徑的埠號

  • /goods 代表的是指定頁面(路徑)

  • goodsIdname 代表傳遞的兩個引數

3.6.3 Scheme使用

  • 定義一個 Scheme

  • 獲取 Scheme 跳轉的引數

  • 呼叫方式
  1. 原生呼叫

  1. html呼叫

  1. 判斷某個Scheme是否有效

  • 關於scheme跳轉協議,可以檢視下面的部落格,站在巨人的肩膀上,才能看得更遠
    Android產品研發(十一)-->應用內跳轉Scheme協議


# 4. Context

4.1 Context , Activity , Appliction 的區別

  • 相同:ActivityApplication 都是 Context 的子類。
  • Context 從字面上理解就是上下文的意思, 在實際應用中它也確實是起到了管理 上下文環境中各個引數和變數的總用, 方便我們可以簡單的訪問到各種資源。
  • 不同:維護的生命週期不同。Context 維護的是當前的 Activity 的生命週期, Application 維護的是整個專案的生命週期。
  • 使用 context 的時候, 小心記憶體洩露, 防止記憶體洩露

4.2 Context 是什麼

  • 它描述的是一個應用程式環境的資訊,即上下文。

  • 該類是一個抽象( abstract class )類, Android 提供了該抽象類的具體實 現類( ContextIml )。

  • 通過它我們可以獲取應用程式的資源和類, 也包括一些應用級別操作, 例如:啟動一個 Activity ,傳送廣播,接受 Intent ,資訊,等。

4.2.1 附加一張 Context 繼承關係圖

4.3 獲取當前螢幕 Activity 的物件

  • 使用 ActivityLifecycleCallbacks
    Android 如何獲取當前Activity例項物件?

4.4 Activity 的管理機制

  • Activity的管理機制

  • 面試官問這個問題,想看看大家對Activity瞭解是否深入:
  1. 什麼是 ActivityRecord
  2. 什麼是 TaskRecord
  3. 什麼是 ActivityManagerService

4.5 什麼是 Activity

  • 四大元件之一,通常一個使用者互動介面對應一個 activity
  • activityContext 的子類,同時實現了 window.callbackkeyevent.callback ,可以處理與窗體使用者互動的事件。
  • 開發中常用的有 FragmentActivityListActivityTabActivityAndroid 4.0Fragment 取代)

# 5. 程序

5.1 Android 程序優先順序

  • 前臺 / 可見 / 服務 / 後臺 / 空

5.1.1 前臺程序:Foreground process

  • 使用者正在互動的 ActivityonResume()
  • 當某個 Service 繫結正在互動的 Activity
  • 被主動呼叫為前臺 ServicestartForeground()
  • 元件正在執行生命週期的回撥( onCreate()onStart()onDestory()
  • BroadcastReceiver 正在執行 onReceive()

5.1.2 可見程序:Visible process

  • 我們的 Activity 處在 onPause()(沒有進入 onStop()
  • 繫結到前臺 ActivityService

5.1.3 服務程序:Service process

  • 簡單的 startService() 啟動。

5.1.4 後臺程序:Background process

  • 對使用者沒有直接影響的程序 --- Activity 處於 onStop() 的時候。
  • android:process=":xxx"

5.1.5 空程序:Empty process

  • 不含有任何的活動的元件。( Android 設計的,處於快取的目的,為了第二次啟動更快,採取的一個權衡)

5.2 可見程序

可見程序指部分程式介面能夠被使用者看見,卻不在前臺與使用者互動的程序。例如,我們在一個介面上彈出一個對話方塊(該對話方塊是一個新的 Activity ),那麼在對話方塊後面的原介面是可見的,但是並沒有與使用者進行互動,那麼原介面就是可見程序。

  • 一個程序滿足下面任何一個條件都被認為是可視的:
  1. 寄宿著一個不是前臺的活動,但是它對使用者仍可見(它的 onPause() 方法已經被呼叫)。舉例來說,這可能發生在,如果一個前臺活動在一個對話方塊(其他程序的)執行之後仍然是可視的,比如輸入法的彈出時。
  2. 寄宿著一個服務,該服務繫結到一個可視的活動。
  • 一個可視程序被認為是及其重要的且不會被殺死,除非為了保持前臺程序執行。

5.3 服務程序

  • 服務程序是通過 startService() 方法啟動的程序,但不屬於前臺程序和可見程序。例如,在後臺播放音樂或者在後臺下載就是服務程序。

  • 系統保持它們執行,除非沒有足夠記憶體來保證所有的前臺程序和可視程序。

5.4 後臺程序

  • 後臺程序是一個保持著一個當前對使用者不可視的活動(已經呼叫 Activity 物件的 onStop() 方法)(如果還有除了 UI 執行緒外其他執行緒在執行話,不受影響)。

例如我正在使用 qq 和別人聊天,這個時候 qq 是前臺程序,但是當我點選 Home 鍵讓 qq 介面消失的時候,這個時候它就轉換成了後臺程序。

  • 這些程序沒有直接影響使用者體驗,並且可以在任何時候被殺以收回記憶體用於一個前臺、可視、服務程序。
  • 一般地有很多後臺程序執行著,因此它們保持在一個 LRUleast recently used ,即最近最少使用,如果您學過作業系統的話會覺得它很熟悉,跟記憶體的頁面置換演算法 LRU 一樣)列表以確保最近使用最多的活動的程序最後被殺。

5.5 空程序

  • 空程序是一個沒有保持活躍的應用程式元件的程序,不包含任何活躍元件。

  • 保持這個程序可用的唯一原因是作為一個 cache 以提高下次啟動元件的速度。系統程序殺死這些程序,以在程序 cache 和潛在的核心 cache 之間平衡整個系統資源。

  • android 程序的回收順序從先到後分別是:空程序,後臺程序,服務程序,可見程序,前臺程序。

5.6 什麼是 ANR,如何避免

5.6.1 什麼是ANR

  • ANR ,全稱為 Application Not Responding
  • Android 中,如果你的應用程式有一段時間沒有響應,系統會向用戶顯示一個對話方塊,這個對話方塊稱作應用程式無響應對話方塊。

5.6.2 使用者行為

  • 使用者可以選擇讓程式繼續執行,也可以讓程式停止執行。
  • 他們在使用你的應用程式時,並不希望每次都要處理這個對話方塊。
  • 因此,在程式裡對響應效能的設計很重要,這樣,系統不會顯示 ANR 給使用者。

5.6.3 Android不同元件ANR超時時間不同

  • 不同的元件發生 ANR 的時間不一樣,主執行緒( ActivityService )是 5 秒,BroadCastReceiver10 秒。

5.6.4 解決方案

  1. 將所有耗時操作,比如訪問網路,Socket 通訊,查詢大量 SQL 語句,複雜邏輯計算等都放在子執行緒中去,然後通過 handler.sendMessagerunonUITreadAsyncTask 等方式更新 UI ,以確保使用者介面操作的流暢度。
  2. 如果耗時操作需要讓使用者等待,那麼可以在介面上顯示進度條。

5.7 android的任務棧 Task

  • 一個 Task 包含的就是 activity 集合,android 系統可以通過任務棧有序的管理 activity
  • 一個app當中可能不止一個任務棧,在某些情況下,一個 activity 也可以獨享一個任務棧( singleInstance 模式啟動的 activity

# 總結

  1. 本文基本涵蓋了 Android Activity 的所有知識點。對於 App 啟動、AMS 希望大家能根據文中連結或者 Google 搜尋的形式繼續展開學習。
  2. 重點:關於 Android 的四大元件,到現在為止我才總結完 Activity ,馬上我將繼續針對,ServiceBroadcastRecevier 等,以及事件分發、滑動衝突、新能優化等重要模組,進行全面總結,歡迎大家關注 _yuanhao 的 部落格園 ,方便及時接收更新

碼字不易,你的點贊是我總結的最大動力!


  • 由於我在「稀土掘金」「簡書」「CSDN」「部落格園」等站點,都有新內容釋出。所以大家可以直接關注我的 GitHub 倉庫,以免錯過精彩內容!

  • 倉庫地址:
    超級乾貨!精心歸納 AndroidJVM 、演算法等,各位帥氣的老鐵支援一下!給個 Star !

  • 一萬多字長文,加上精美思維導圖,記得點贊哦,歡迎關注 _yuanhao 的 部落格園 ,我們下篇文章見!