Android面試題集:以前爛大街的四大組件-Activity,面試重提這些知識點你還記得嗎?

前言

雖然有很多面試的文章裏都有這些題目,但是我每次在看的時候,總是會覺得有些分散,複習的時候還要重新去找到對應的文章,所以我就想着自己來整理一下,並且把題目給分一下類型;自己整理可以幫助我複習的同時還可以鞏固一遍;這次主要是4大組件相關,後續我會繼續整理,覺得有幫助的可以點個贊。

今天先分享的是關於Activity的面試題:

描述一下Activity 生命週期?

  • onCreate() Activity第-次被創建的時候調用,一些初始化操作可以在這裏完成。
  • onStart() 這個方法在Activity 由不可見變爲可見的時候調用。
  • onResume() 這個方法在Activity 準備好和用戶進行交互的時候調用。此時的Acivity一定位於返回棧的棧頂,並且處於運行狀態。
  • onPause() 這個方法在系統準備去啓動或者恢復另-個Activity的時候調用。
  • onStop() 這個方法在Activity 完全不可見的時候調用。它和onPause()方法的主要區別在於,如果啓動的新Activity 是一個對話框式的Activity,那麼onPause()方法會得到執行,而onStop()方法並不會執行。
  • onDestroy() 這個方法在Activity被銷燬之前調用,之後Activity的狀態將變爲銷燬狀態。
  • onRestart 這個方法在Activity由停止狀態變爲運行狀態之前調用,也就是Activity被重新啓動了。

生命週期:爲了鞏固記憶,畫了一遍。

Activity之間跳轉時的生命週期

A Activity 打開 B Activity 時都有哪些生命週期回調?

A.onPause -> B.onCrete -> B.onStart -> B.onResume -> A.onStop

這樣回答只是及格,因爲僅在 B Activity 的 launchMode 爲 standard 或者 B Activity 沒有可複用的實例時是這樣的。

當 B Activity 的 launchMode 爲 singleTop 且 B Activity 已經在棧頂時(一些特殊情況如通知欄點擊、連點),此時只有 B 頁面自己有生命週期變化:

B.onPause -> B.onNewIntent -> B.onResume

當 B Activity 的 launchMode 爲 singleInstance ,singleTask 且對應的 B Activity 有可複用的實例時,生命週期回調是這樣的:

A.onPause -> B.onNewIntent -> B.onRestart -> B.onStart -> B.onResume -> A.onStop -> ( 如果 A 被移出棧的話還有一個 A.onDestory)

Activity的啓動模式

有4種啓動模式:

  • standard 標準模式
  • singleTop 棧頂複用模式
  • singleTask 棧內複用模式
  • singleInstance 單例模式

標準模式:每次啓動時,都會創建一個新的實例在棧頂
棧頂複用模式:如果需要新創建的實例就在棧頂,那麼就不會去重建,而是重用,否則就重新創建。
棧內複用模式:如果實例在當前棧中已經存在,就會將當前實例上面的其他實例都移除棧。
單例模式:直接創建一個新的棧並且創建實例放在棧中。

使用方式
1.可以在在AndroidMainifest的Activity配置進行設置:android:launchMode="啓動模式"
2.通過 Intent設置標誌位

val intent=Intent(this,SocendActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
//其中標誌位屬性
FLAGACTIVITYSINGLE_TOP:指定啓動模式爲棧頂複用模式( SingleTop)
FLAGACTIVITYNEW_TASK: 指定啓動模式爲棧內複用模式( SingleTask)
FLAGACTIVITYCLEAR_TOP:所有位於其上層的Activity都要移除, SingleTask模式默認具有此標記效果
FLAGACTIVITYEXCLUDEFROMRECENTS:具有該標記的Activity不會出現在歷史Activity的列表中,即無法通過歷史列表回到該Activity上

那麼這兩種方式有什麼區別呢?

  • 優先級不同 Intent設置方式的優先級 > Manifest設置方式,即 以前者爲準
  • 限定範圍不同 Manifest設置方式無法設定 FLAG_ACTIVITY_CLEAR_TOP; Intent設置方式 無法設置單例模式( SingleInstance)

onStart,onStop和onResume,onPause的區別?

Activity的生命週期中,大部分都是兩兩相對的,可以將其分爲3種,前臺,可見,後臺。 onStart,onStop之間所經歷的是可見的,但是卻可能無法與用戶交互。 onResume,onPause之間所經歷的是屬於前臺,這時候用戶是可以交互的。

如果新Activity是透明主題時,舊Activity會不會走onStop?

不會!

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

鎖屏時只會調用onPause(),而不會調用onStop方法,開屏後則調用onResume()。

橫豎屏切換時的生命週期?

如果清單文件中沒有設置android:configChanges屬性時,生命週期:先銷燬onPause()、onStop()、onDestroy()再重新創建onCreate()、onStart()、onResume()方法。
設置orientation|screenSize(一定要同時出現)屬性值時,不走生命週期方法,只會執行onConfigurationChanged()方法。

彈出 Dialog 對生命週期有什麼影響?

我們知道,生命週期回調都是 AMS 通過 Binder 通知應用進程調用的;而彈出 Dialog、Toast、PopupWindow 本質上都直接是通過 WindowManager.addView() 顯示的(沒有經過 AMS),所以不會對生命週期有任何影響。

如果是啓動一個 Theme 爲 Dialog 的 Activity , 則生命週期爲:

A.onPause -> B.onCrete -> B.onStart -> B.onResume

注意:這邊沒有前一個 Activity 不會回調 onStop,因爲只有在 Activity 切到後臺不可見纔會回調 onStop;而彈出 Dialog 主題的 Activity 時前一個頁面還是可見的,只是失去了焦點而已所以僅有 onPause 回調。

Activity 在 onResume 之後才顯示的原因是什麼?

雖然我們設置 Activity 的佈局一般都是在 onCreate 方法裏調用 setContentView 。裏面是直接調用 window 的 setContentView,創建一個 DecorView 用來包住我們創建的佈局。詳情如下:

PhoneWindow.java
public void setContentView(int layoutResID) {
 if (mContentParent == null) {
 installDecor();
 } 
 ...
 // 加載佈局,添加到 mContentParent
 // mContentParent 又是 DecorView 的一個子佈局 
 mLayoutInflater.inflate(layoutResID, mContentParent);
}

然而這一步只是加載好了佈局,生成一個 ViewTree , 具體怎麼把 ViewTree 顯示出來,答案就在下面:

ActivityThread.java
public void handleResumeActivity(...){
 // onResume 回調
 ActivityClientRecord r = performResumeActivity(...)
 final Activity a = r.activity;
 if (r.window == null && !a.mFinished && willBeVisible) {
 r.window = r.activity.getWindow();
 View decor = r.window.getDecorView();
 ViewManager wm = a.getWindowManager();
 wm.addView(decor, l);// 重點
 }
}

WindowManager 的 addView 方法最終將 DecorView 添加到 WMS ,實現繪製到屏幕、接收觸屏事件。具體的調用鏈如下:

WindowManagerImpl.addView
-> WindowManagerGlobal.addView
-> ViewRootImpl.setView     
-> ViewRootImpl.requestLayout() // 執行 View 的繪製流程
 // 通過 Binder 調用 WMS ,WMS 會添加一個 Window 相關的對象
 // 應用端通過 mWindowSession 調用 WMS
 // WMS 通過 mWindow (一個 Binder 對象) 調用應用端 
 mWindowSession.addToDisplay(mWindow)

綜上,在onResume回調之後,會創建一個 ViewRootImpl ,有了它之後應用端就可以和 WMS 進行雙向調用了。

onActivityResult 在哪兩個生命週期之間回調?

onActivityResult 不屬於 Activity 的生命週期,一般被問到這個問題時大家都會懵逼。

其實答案很簡單,onActivityResult 方法的註釋中就寫着答案:

「You will receive this call immediately before onResume() when your activity is re-starting.」

跟一下代碼(TransactionExecutor.execute 有興趣的可以自己打斷點跟一下),會發現 onActivityResult 回調先於該 Activity 的所有生命週期回調,從 B Activity 返回 A Activity 的生命週期調用爲:

B.onPause -> A.onActivityResult -> A.onRestart -> A.onStart -> A.onResume

onCreate 方法裏寫死循環會 ANR 嗎?

ANR 的四種場景:

  • Service TimeOut: service 未在規定時間執行完成:前臺服務 20s,後臺 200s
  • BroadCastQueue TimeOut: 未在規定時間內未處理完廣播:前臺廣播 10s 內, 後臺 60s 內
  • ContentProvider TimeOut: publish 在 10s 內沒有完成
  • Input Dispatching timeout: 5s 內未響應鍵盤輸入、觸摸屏幕等事件

我們可以看到,Activity 的生命週期回調的阻塞並不在觸發 ANR 的場景裏面,所以並不會直接觸發 ANR。
只不過死循環阻塞了主線程,如果系統再有上述的四種事件發生,就無法在相應的時間內處理從而觸發 ANR。

onNewIntent是什麼時候調用的?

如果需要啓動的實例是之前有打開過的,並且在棧的頂部,目前處於onPause、onStop 的狀態,其他實例再次進入的話,執行順序爲:onNewIntent,onRestart,onStart,onResume。

onSaveInstanceState()方法的作用?

異常情況下系統配置發生改變時導致Activity被殺死並重新創建、資源內存不足導致低優先級的Activity被殺死

  • 系統會調用onSaveInstanceState來保存當前Activity的狀態,此方法調用在onStop之前,與onPause沒有既定的時序關係;
  • 當Activity被重建後,系統會調用onRestoreInstanceState,並且把onSave(簡稱)方法所保存的Bundle對象同時傳參給onRestore(簡稱)和onCreate(),因此可以通過這兩個方法判斷Activity是否被重建,調用在onStart之後;

Activity跟window,view之間的關係?

  • Activity在創建時會調用 attach() 方法初始化一個PhoneWindow(繼承於Window),每一個Activity都包含了唯一一個PhoneWindow
  • Activity通過setContentView實際上是調用的getWindow().setContentView將View設置到PhoneWindow上而PhoneWindow內部是通過WindowManager的addView、removeView、updateViewLayout這三個方法來管理View,WindowManager本質是接口,最終由WindowManagerImpl實現

App的啓動流程

1、點擊桌面App圖標,Launcher進程採用Binder IPC向system_server進程發起startActivity請求;
2、system_server進程接收到請求後,向zygote進程發送創建進程的請求;
3、Zygote進程fork出新的子進程,即App進程;
4、App進程,通過Binder IPC向sytem_server進程發起attachApplication請求;
5、system_server進程在收到請求後,進行一系列準備工作後,再通過binder IPC向App進程發送scheduleLaunchActivity請求;
6、App進程的binder線程(ApplicationThread)在收到請求後,通過handler向主線程發送LAUNCH_ACTIVITY消息;
7、主線程在收到Message後,通過發射機制創建目標Activity,並回調Activity.onCreate()等方法。

最後分享一波面試複習路線

多餘的話就不講了,接下來將分享面試的一個複習路線,如果你也在準備面試但是不知道怎麼高效複習,可以參考一下我的複習路線,有任何問題也歡迎一起互相交流,加油吧!

這裏給大家提供一個方向,進行體系化的學習:

1、看視頻進行系統學習

前幾年的Crud經歷,讓我明白自己真的算是菜雞中的戰鬥機,也正因爲Crud,導致自己技術比較零散,也不夠深入不夠系統,所以重新進行學習是很有必要的。我差的是系統知識,差的結構框架和思路,所以通過視頻來學習,效果更好,也更全面。關於視頻學習,個人可以推薦去B站進行學習,B站上有很多學習視頻,唯一的缺點就是免費的容易過時。

另外,我自己也珍藏了好幾套視頻,有需要的我也可以分享給你。

2、進行系統梳理知識,提升儲備

客戶端開發的知識點就那麼多,面試問來問去還是那麼點東西。所以面試沒有其他的訣竅,只看你對這些知識點準備的充分程度。so,出去面試時先看看自己複習到了哪個階段就好。

系統學習方向:

  • 架構師築基必備技能:深入Java泛型+註解深入淺出+併發編程+數據傳輸與序列化+Java虛擬機原理+反射與類加載+動態代理+高效IO

  • Android高級UI與FrameWork源碼:高級UI晉升+Framework內核解析+Android組件內核+數據持久化

  • 360°全方面性能調優:設計思想與代碼質量優化+程序性能優化+開發效率優化

  • 解讀開源框架設計思想:熱修復設計+插件化框架解讀+組件化框架設計+圖片加載框架+網絡訪問框架設計+RXJava響應式編程框架設計+IOC架構設計+Android架構組件Jetpack

  • NDK模塊開發:NDK基礎知識體系+底層圖片處理+音視頻開發

  • 微信小程序:小程序介紹+UI開發+API操作+微信對接

  • Hybrid 開發與Flutter:Html5項目實戰+Flutter進階

知識梳理完之後,就需要進行查漏補缺,所以針對這些知識點,我手頭上也準備了不少的電子書和筆記,這些筆記將各個知識點進行了完美的總結。

3、讀源碼,看實戰筆記,學習大神思路

“編程語言是程序員的表達的方式,而架構是程序員對世界的認知”。所以,程序員要想快速認知並學習架構,讀源碼是必不可少的。閱讀源碼,是解決問題 + 理解事物,更重要的:看到源碼背後的想法;程序員說:讀萬行源碼,行萬種實踐。

主要內含微信 MMKV 源碼、AsyncTask 源碼、Volley 源碼、Retrofit源碼、OkHttp 源碼等等。

4、面試前夕,刷題衝刺

面試的前一週時間內,就可以開始刷題衝刺了。請記住,刷題的時候,技術的優先,算法的看些基本的,比如排序等即可,而智力題,除非是校招,否則一般不怎麼會問。

關於面試刷題,我個人也準備了一套系統的面試題,幫助你舉一反三:

總結

改變人生,沒有什麼捷徑可言,這條路需要自己親自去走一走,只有深入思考,不斷反思總結,保持學習的熱情,一步一步構建自己完整的知識體系,纔是最終的制勝之道,也是程序員應該承擔的使命。

以上內容均免費分享給大家,需要完整版的朋友,點這裏可以看到全部內容。或者關注主頁掃描加 微信 獲取。

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