Activity面試指南與面試題精選

文章目錄


提起四大組件之首Activity,想必是無人不知無人不曉,不論多麼初級的android工程師都會比較瞭解,接下來就總結下關於Activity的面試題。

1.生命週期

返回棧

Q:談一下返回棧

首先理解android是使用Task來管理活動,一個Task就是一組存放在棧裏的活動的集合,這個棧就叫做返回棧,每啓動一個新的活動,就會將其放入棧頂,當我們點擊back回退或調用activity的finish函數處於棧頂的活動就會出棧,前一個入棧的活動就會到棧頂,系統總是顯示處於棧頂的活動。

活動生命週期

Q:說下Activity的生命週期?

在這裏插入圖片描述

  1. onCreate()方法:活動第一次創建的時候被調用,常做初始化的操作,比如加載佈局(setContentView),綁定事件(findViewById)。表示Activity正在創建
  2. onStart()方法:活動由不可見到可見的時候被調用,表示Activity正在啓動,此時Activity可見但不在前臺
  3. onResume()方法:活動準備好和用戶進行交互時調用。表示Acitivity獲得焦點,此時Activity可見且在前臺
  4. onPause()方法:系統準備去啓動或恢復另一個活動時調用。表示Activity正在停止,此時可做存儲數據,停止動畫等操作。
  5. onStop()方法:在活動完全不可見的時候調用。表示Activity即將停止
  6. onDestory()方法:在活動被銷燬之前調用,表示Activity即將銷燬,常做回收工作、資源釋放
  7. onRestart()方法:在活動由停止狀態變爲運行狀態之前調用。表示Activity即將重啓

Q:說下活動的生存期/(onStart方法/onStop()方法與onResume()方法/onPause()方法有什麼區別)

活動的生存期分爲三個:1.完整生存期 2.可見生存期 3.前臺生存期
完整生存期:onCreate()方法與onDestory()都處於完整生存期,一般情況下,Activity會在onCreate()方法中完成各種初始化操作,而在onDestory()方法中完成釋放內存的操作。
可見生存期:onStart()方法與onStop()方法就是可見生存期Activity對於用戶是可見的,但無法與用戶交互。onStart()方法中對資源進行加載,onStop()方法中對資源進行釋放。
前臺生存期:onResume方法與onPause方法就是前臺生存期,在前臺生存期內,活動處於運行狀態,此時可以與用戶交互。

Q:說下Activity處於onPasue()下可以執行那些操作?

1.用戶返回該Activity,調用onResume()方法,重新running
2.用戶打開了其他Activity,就會調用onStop()方法
3.系統內存不足,擁有更高權限的應用需要內存,該Activity就會被系統回收
4.如果用戶返回到onStop()的Activity又顯示在前臺了,系統會調用

onRestart() -> onStart() -> onResume() 然後重新running

當Activity結束(調用finish()方法)就會調用onDestory()方法釋放所有佔用的資源。

生命週期的切換過程

1.啓動一個Activity

onCreate->onStart->onResume

2.當一個Activity打開另一個Activity都會回調哪些方法,如果ActivityB是完全透明的呢,如果啓動的是一個對話框Activity呢?

A:onPause->B:onCreate->B:onStart->B:onResume->A:onStop
如果ActivityB是完全透明的或對話框Activity則不會調用onStop。

3.啓動新Activity後,又返回到舊的Activity

B:onPause->A:onRestart->A:onStart->A:onResume->B:onStop->B:onDestory

4.關閉屏幕/按Home鍵:

onPause->onStop

5.當一個Activity按Home鍵切換到桌面後又回到該Activity回調哪些方法。

onPause->onStop->onRestart->onStart->onResume

6.當一個Activity按back鍵回退時回調哪些方法

onPause->onStop->onDestory

Activity的優先級

1.可見且可以交互(前臺Acitivity):正在和用戶交互,優先級最高。
2.可見但不可以交互(可見但非前臺Activity):比如當前Activity啓動了一個對話框Activity,當前Activity就是可見但不可以交互。
3.後臺Activity:已經被暫停的Activity,比如執行了onStop,優先級最低。
當系統內存不足,會按照優先級順序從低到高去殺死目標Activity所在的進程。

Q:(1)優先級低的Activity在內存不足被回收後怎樣做可以恢復到銷燬前狀態?/(2)橫豎屏切換後怎樣做可以恢復到銷燬前狀態?

回答:優先級低的Activity在內存不足被回收後重新打開(橫豎屏切換的過程中)會引發Activity重建。
在Activity由於異常情況被終止時,系統會調用onSaveInstanceState方法來保存當前Activity的狀態,該方法調用於onStop之前,與onPause方法沒有時序關係。當異常終止的Activity被重建時,會調用onRestoreInstanceState方法(該方法在onStart之後),並且把Activity銷燬時onSaveInstanceState保存的Bundle對象參數同時傳遞給onCreate方法onRestoreInstanceState方法。該方法的調用是在onStart之前。因此可通過onRestoreInstanceState(Bundle savedInstanceState)和onCreate((Bundle savedInstanceState)來判斷Activity是否被重建,並取出數據進行恢復。但需要注意的是,在onCreate取出數據時一定要先判斷savedInstanceState是否爲空。
補充:其中onCreate和onRestoreInstanceState方法來恢復Activity的狀態的區別
onRestoreInstanceState方法回調則說明bundle對象非空,不需要加非空判斷,而onCreate需要非空判斷。

Q:談談onSaveInstanceState() 與 onRestoreIntanceState()

onSaveInstanceState()

這兩個方法並不是生命週期方法,它們並不一定會被觸發。當應用遇到意外情況(如:內存不足、用戶直接按Home鍵)由系統銷燬一個Activity時,onSaveInstanceState() 會被調用,該方法的調用在onStop之前,與onPause沒有時序關係但是當用戶主動去銷燬一個Activity時,例如在應用中按返回鍵,onSaveInstanceState()就不會被調用。因爲在這種情況下,用戶的行爲決定了不需要保存Activity的狀態。
onSaveInstanceState()時機:
(1)用戶按下Home鍵
(2)橫豎屏切換
(3)按下電源按鈕(關閉屏幕顯示)
(4)內存不足導致優先級的Activity被殺死

onRestoreIntanceState()

當被系統異常銷燬的Activity被重建時,會調用onRestoreIntanceState或onCreate方法來恢復,而onRestoreInstance與Oncreate方法中傳入的Bundle對象是銷燬時onSaveInstanceState保存的,onRestoreIntanceState在onStart之後。

Q:onSaveInstanceState()與onPause()的區別?

onSaveInstanceState()只適合用於保存一些臨時性的狀態,而onPause()適合用於數據的持久化保存。

Q:談談橫豎屏切換過程中調用的函數

要切記這裏活動已經被銷燬了。
onPause->onSaveInstanceState->onStop->onDestory()->onCreate->onStart->onRestoreIntanceState->onResume

Q:如何防止橫豎屏切換(配置改變)時Activity銷燬並切換

通過對AndroidManifest文件的Activity中指定(configChanges)屬性:

android:configChanges = “orientation| screensize”

來避免橫豎屏切換時,Activity的銷燬和重建,而是回調了onCofigurationChanged()方法

@Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }

這裏附上android configChanges的所有屬性解釋

“mcc“ 移動國家號碼,由三位數字組成,每個國家都有自己獨立的MCC,可以識別手機用戶所屬國家。
“mnc“ 移動網號,在一個國家或者地區中,用於區分手機用戶的服務商。
“locale“ 所在地區發生變化。
“touchscreen“ 觸摸屏已經改變。(這不應該常發生。)
“keyboard“ 鍵盤模式發生變化,例如:用戶接入外部鍵盤輸入。
“keyboardHidden“ 用戶打開手機硬件鍵盤
“navigation“ 導航型發生了變化。(這不應該常發生。)
“orientation“ 設備旋轉,橫向顯示和豎向顯示模式切換。
“fontScale“ 全局字體大小縮放發生改變

生命週期的記憶方法

流程圖

參考鏈接
這個onRestart其實應該畫在onStart方法上面。
在這裏插入圖片描述
這裏是想說明這些方法是兩兩對應的。onCreate創建與onDestory銷燬,onStart方法Activity可見與onStop方法Activity不可見,而onResume方法獲得焦點(在前臺)與onPause方法取消焦點(不在前臺)。而onRestart方法是在onStop後再次啓動Activity時調用,下一步會直接調用onStart方法如果之前Activity調用了onDestory(被銷燬)之後再次啓動就會調用onCreate

切換過程的比喻

把Activity比作書本。書本現在都放置在書架上,我們想要閱讀一本書(啓動Activity),首先先將書從書架上拿下來(onCreate),然後放在桌子上準備讀(onStart),之後我們打開書本開始讀並做一些筆記(onResume)。

這個時候如果我們想要閱讀另一本書,就要先合上書1(書1:onPause),然後從書架拿另一本書(書2:onCreate),然後放在桌子上並打開(書2:onStart,onResume)。
如果書1被完全蓋住(就調用書1:onStop),如果沒有被完全蓋住就不調用onStop(比如書2是透明的,或書2是彈窗型Activity)。

我們也可以將書1返回書架(onDestory)。

2.Activity啓動模式

1.android提供了四種Activity啓動模式:
標準模式(standard)
棧頂複用模式(singleTop)
棧內複用模式(singleTask)
單例模式(singleInstance)
2. activity的管理是採用任務棧的形式,上文中已經提過。
在這裏插入圖片描述

1.Standard模式(標準模式)

標準模式就是我們最常用的模式,在該模式下,每當啓動一個新的活動,它就會在返回棧中入棧,並處於棧頂的位置。該模式不會考慮活動是否已經存在棧中,每次啓動都會創建該活動的一個新的實例

下面來看第一行代碼中的例子。
在這裏插入圖片描述
運行程序,然後在FirstActivity中連續點擊兩次按鈕,觀察logcat中打印信息。
在這裏插入圖片描述
可以看到,每點擊一次按鈕就會創建一次FirstActivity的實例,此時返回棧中也會存在3個FirstActivity的實例,因此你需要連按3次Back鍵才能退出程序。

2.singleTop(棧頂複用模式)

如果需要新創建的Activity處於棧頂的話,那麼Activity的實例就不會重建,而是重用棧頂的實例,並回調如下方法:

   @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
    }

流程如下,當棧頂爲ActivityA,而我們又一次要啓動ActivityA,任務棧就不會繼續增加ActivityA的實例,直接重用棧頂的實例。
在這裏插入圖片描述
如果棧頂不是新建的Activity,就會創建Activity新的實例,並放入棧頂。這裏有個問題就是說比如我們重新調用的Activity處於任務棧中,但不位於棧頂的話,還是會創建實例。

下面來看第一行代碼中的例子
我們讓FirstActivity中的button1通過點擊可以跳轉到SecondActivity。
在這裏插入圖片描述
我們讓SecondActivity的button2通過點擊可以跳轉到FirstActivity。
在這裏插入圖片描述
之後運行程序,在FirstActivity界面點擊按鈕進入到SecondActivity,然後在SecondActivity界面點擊按鈕,又會重新進入到FirstActivity。
在這裏插入圖片描述
當前Activity爲SecondActivity時,任務棧task爲【SecondActivity,FirstActivity】,此時點擊button,跳轉到FirstActivity,棧頂並非爲FirstActivity,於是又會創建FirstActivity,並壓入任務棧中,任務棧task爲【FirstActivity,SecondActivity,FirstActivity】。

應用場景

1.在通知欄點擊收到的通知,然後需要啓動一個Activity,這個Activity就可以用singleTop,否則每次點擊都會新建一個Activity。
2.防止快速多次點擊Activity,多次啓動。

3.singleTask模式(棧內複用模式)

與棧頂複用模式相對的,就是棧內複用模式,即一個棧內只有一個Activity的實例。可以在AndroidMainfest文件的Activity中指定該Activity需要加載到哪個棧中,即singleTask的Activity可以指定想要加載的目標棧。singleTask和taskAffinity配合使用,指定開啓的Activity加入到哪個棧中。

<activity android:name=".Activity1"
	android:launchMode="singleTask"
	android:taskAffinity="com.lvr.task"
	android:label="@string/app_name">
</activity>

關於taskAffinity的值: 每個Activity都有taskAffinity屬性,這個屬性指出了它希望進入的Task。如果一個Activity沒有顯式的指明該Activity的taskAffinity,那麼它的這個屬性就等於Application指明的taskAffinity,如果Application也沒有指明,那麼該taskAffinity的值就等於包名。

下面來看第一行代碼的實例。
繼續使用singleTop中的FirstActivity和SecondActivity,並將FirstActivity的啓動模式更改爲SingleTask模式。
在這裏插入圖片描述
之後在FirstActivity中添加onRestart()方法,並打印日誌。
在這裏插入圖片描述
最後在SecondActivity中添加onDestory()方法,並打印日誌。
在這裏插入圖片描述
重新運行程序,在FirstActivity界面點擊按鈕進入到SecondActivity,然後在SecondActivity界面點擊按鈕,又會重新進入到FirstActivity。
在這裏插入圖片描述
可以看到在SecondActivity中啓動FirstActivity時,會發現棧中已經有了FirstActivity的實例,並且在SecondActivity的下面,於是會讓SecondActivity出棧,而FirstActivity又重新變成棧頂的Actiivity,因此會調用FirstActivity的onRestart方法與SecondActivity的onDestory方法,此時任務棧中只有FirstActivity。下圖很好的說明了這個過程。
在這裏插入圖片描述
其實剛纔說的這種情況前提在於FirstAcitivity指定要加載的棧(taskAffinity)爲默認的棧。
因此該種啓動模式有三種情況:
1.以singleTask啓動ActivityD,同時其所需任務棧(taskAffinity)s1。當前情況下,存在s1棧,但s1棧中沒有ActivityD,直接task1中壓入ActivityD。
在這裏插入圖片描述
2.當前情況與第一行代碼中情況類似。當前情況下,s1棧中存在ActivityB,因此需要將處於ActivityB上面的Activity全部出棧。
在這裏插入圖片描述
3.該情況爲一種特殊情況,我們打算以singleTask啓動ActivityD,比較棧爲s2。而當前存在的棧爲s1,沒有s2任務棧,因此就直接創建一個新的棧,並將Activity壓入。
在這裏插入圖片描述
總結:以SingleTask方式啓動Activity時,會與指定的棧(如果沒有指定就是默認棧)進行比較,如果該棧中存在該Activity就把棧中該Activity之上的Activity全部出棧,如果該棧中不存在該Activity就直接將該Acitivity壓入棧中。

應用場景

應用於首頁或登錄頁,用戶在點擊後退鍵可直接退出應用。
多數App的主頁。對於大部分應用,當我們在主界面點擊回退按鈕的時候都是退出應用,那麼當我們第一次進入主界面之後,主界面位於棧底,以後不管我們打開了多少個Activity,只要我們再次回到主界面,都應該使用將主界面Activity上所有的Activity移除的方式來讓主界面Activity處於棧頂,而不是往棧頂新加一個主界面Activity的實例,通過這種方式能夠保證退出應用時所有的Activity都能被銷燬。

4.singleInstance(單例模式)

一看singleInstance其實就能想到是單例,以該模式啓動Activity,就會直接創建一個新的任務棧,並創建該Activity的實例放入新棧中,一旦該模式的Activity實例已經存在於某個棧中,任何應用激活該Activity時都會重用該棧中的實例。
在這裏插入圖片描述

應用場景

呼叫來電界面。

面試題彙總

Q: 說下Activity的四種啓動模式?

1.standard模式(標準模式):普通啓動模式,每次啓動Activity時,就會創建一個實例。
2.singletop模式(棧頂模式):當啓動Activity時,會判斷任務棧的棧頂是否爲該Activity,如果是該Activity則不會創建實例,去**回調onNewIntent(intent)方法,否則會創建實例
3.singletask模式(棧內模式):當啓動Activity時,只要該Activity在指定的棧中,就不會創建實例,去回調
onNewIntent(intent)**方法。如果不存在,會判斷是否指定的棧不存在,就創建一個棧並將Activity的實例壓入,如果指定的棧存在,就直接壓入該棧中。
4.singleInstance模式(單實例模式):該模式下,創建Activity實例時,直接創建一個棧,棧中只有該Activity實例。之後無論哪個應用程序啓動該Activity,都只會調用棧中該實例。

Q:談談singleTop和singleTask的區別以及應用場景

singleTop模式的含義是(參考上面問題),singleTask模式的含義是(參考上面問題),因此二者的差別爲:
singleTop模式:該模式下,任務棧中可能有多個相同Activity實例,因爲它只是判斷當前啓動的Activity是否在棧頂。
該模式的Activity會默認進入啓動它所屬的任務棧,不涉及任務棧的轉換。常用於防止快速連續點擊而創建多個Activity實例。
singleTask模式:該模式向,任務棧中只會有一個Activity實例,因爲它會判斷當前啓動的Activity是否在當前指定的棧中。該模式下Activity可以通過taskAffinity去指定需要的任務棧,可能涉及任務棧的轉換,常用於首頁或登錄頁。因爲不論我們在進入首頁後進入了多少個Activity,當我們返回首頁後,還是希望退出首頁直接可以退出應用。該模式下會把棧中位於要啓動的Activity上面的Activity都出棧。

Q:onNewIntent()調用時機?

有兩個調用時機,分別是singleTop模式下與singleTask模式下啓動Activity。
singleTop模式:當啓動的Activity是在任務棧的棧頂時,會回調onNewIntent方法。
singleTask模式:當啓動的Activity存在於任務棧中,會回調onNewIntent方法。

Q:瞭解哪些Activity啓動模式的標記位?

  • FLAG_ACTIVITY_SINGLE_TOP:對應singleTop啓動模式
  • FLAG_ACTIVITY_NEW_TASK:對應singleTask模式

Intent啓動與匹配

1.顯式啓動與隱式啓動

  • 顯式啓動

構建一個Intent對象,並傳入FirstActivity.this作爲上下文,並傳入SecondActivity.class作爲目標活動
在這裏插入圖片描述

  • 隱式啓動
    首先在我們需要跳轉的Activity中配置一個< intent-filter>
    在這裏插入圖片描述
    其中包括< action>標籤與< category>標籤,action標籤代表當前活動可以響應當前action,而category標籤則包含了一些附加信息。只有當Activity中的 < action>標籤與< category>標籤同時匹配intent中的< action>標籤與< category>標籤,這個Activity纔可以響應Intent,也就是說可以跳轉至當前Activity
    下面的代碼是FirstActivity中的部分代碼,通過點擊button1,可以跳轉至SecondActivity。
    在這裏插入圖片描述
    每個intent只能有一個action,但可以有多個category,假如我們做了如下操作,就無法跳轉,因爲沒有Activity可以響應當前的intent。
    在這裏插入圖片描述
隱式啓動的例子

其實隱式啓動有個最直接的例子,就是打開APP後首先顯示的Activity就是隱式啓動。因爲我們爲首先打開的Activiity設置了其intent-filter標籤,標籤中action爲android.intent.action.MAIN,category爲android.intent.category.LAUNCHER

 <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

另一個例子就是BroadCast的工作機制,不論是靜態註冊BroadCastReceiver,還是動態註冊,都要寫IntentFilter標籤的,其中包含想要接收廣播的action。

自定義廣播的發送是通過intent來完成的,創建intent,添加action後,使用sendBroadcast發送廣播。

 Intent intent = new Intent();
 intent.setAction("com.example.aaa.special");
 sendBroadcast(intent);

靜態註冊就是在AndroidManifest中給Receiver寫一個IntentFilter標籤,並寫入想要接收廣播的action。

<receiver
 	android:name=".AnotherReciver"
 	android:enabled="true"
 	android:exported="true">
 	<intent-filter>
		<action android:name="com.example.aaa.special"></action>
	</intent-filter>
</receiver>

而動態註冊需要在Activity中創建Recevier的實例,創建一個IntentFilter實例,並通過addAction添加action。最後使用registerReceiver方法傳入Recevier實例與IntentFilter實例。

private IntentFilter intentFilter;
private NetworkChangeReceiver networkChangeReceiver;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        intentFilter = new IntentFilter();
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        networkChangeReceiver = new NetworkChangeReceiver();
        registerReceiver(networkChangeReceiver,intentFilter);
        }   
	@Override
    protected void onDestroy(){
        super.onDestroy();
        unregisterReceiver(networkChangeReceiver);
    }

2.匹配原則

原則:
1.一個intent只有同時匹配某個Activity的intent-filter中的action、category、data纔算完全匹配,才能啓動
該Activity。
2.一個Activity可以有多個 intent-filter,一個 intent只要成功匹配任意一組 intent-filter,就可以啓動
該Activity。
action匹配原則

1.要求intent中的action必須存在且和一組intent-filter中的action完全相等
2.區分大小寫。

category匹配原則

1.intent可以沒有category,因爲會有默認的值。
2.否則intent中的category要求與那一組intent-filter中的全部category完全相同。

data匹配原則

1.如果intent-filter中有定義data,那麼Intent中也必須也要定義date。
2.data主要由mimeType(媒體類型)和URI組成。在匹配時通過intent.setDataAndType(Uri data, String type)方法對data進行設置。

判斷是否匹配

採用隱式方式啓動Activity時,可以用PackageManagerresolveActivity方法或者IntentresolveActivity方法判斷是否有Activity匹配該隱式Intent。

參考鏈接:

2019校招Android面試題解1.0(上篇)
Android BestNote
《第一行代碼》

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