1. 程式人生 > 其它 >01.Activity詳解

01.Activity詳解

1、Activity和Fragment生命週期有哪些?

2、橫豎屏切換時候Activity的生命週期

不設定Activity的android:configChanges時,切屏會重新回撥各個生命週期,切橫屏時會執行一次,切豎屏時會執行兩次。 設定Activity的android:configChanges="orientation"時,切屏還是會呼叫各個生命週期,切換橫豎屏只會執行一次 設定Activity的android:configChanges="orientation |keyboardHidden"時,切屏不會重新呼叫各個生命週期,只會執行onConfigurationChanged方法

適配 Android 10 橫豎屏切換配置:

orientation|keyboardHidden|screenSize

3. activity的startActivity和context的startActivity區別?

(1)、從Activity中啟動新的Activity時可以直接mContext.startActivity(intent)就好

(2)、如果從其他Context中啟動Activity則必須給intent設定Flag:

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) ;
mContext.startActivity(intent);

4. 怎麼加速啟動Activity?

  • onCreate() 中不執行耗時操作 把頁面顯示的 View 細分一下,放在 AsyncTask 裡逐步顯示,用 Handler 更好。這樣使用者的看到的就是有層次有步驟的一個個的 View 的展示,不會是先看到一個黑屏,然後一下顯示所有 View。最好做成動畫,效果更自然。
  • 利用多執行緒的目的就是儘可能的減少 onCreate() 和 onReume() 的時間,使得使用者能儘快看到頁面,操作頁面。
  • 減少主執行緒阻塞時間。
  • 提高 Adapter 和 AdapterView 的效率。
  • 優化佈局檔案。

5. 直接在Activity中建立一個thread跟在service中建立一個thread之間的區別?

在Activity中被建立:該Thread的就是為這個Activity服務的,完成這個特定的Activity交代的任務,主動通知該Activity一些訊息和事件,Activity銷燬後,該Thread也沒有存活的意義了。

在Service中被建立:這是保證最長生命週期的Thread的唯一方式,只要整個Service不退出,Thread就可以一直在後臺執行,一般在Service的onCreate()中建立,在onDestroy()中銷燬。所以,在Service中建立的Thread,適合長期執行一些獨立於APP的後臺任務,比較常見的就是:在Service中保持與伺服器端的長連線。

6. LaunchMode應用場景

standard,建立一個新的Activity。

singleTop,棧頂不是該型別的Activity,建立一個新的Activity。否則,onNewIntent。

singleTask,回退棧中沒有該型別的Activity,建立Activity,否則,onNewIntent+ClearTop。

注意:

設定了"singleTask"啟動模式的Activity,它在啟動的時候,會先在系統中查詢屬性值affinity等於它的屬性值taskAffinity的Task存在;如果存在這樣的Task,它就會在這個Task中啟動,否則就會在新的任務棧中啟動。因此, 如果我們想要設定了"singleTask"啟動模式的Activity在新的任務中啟動,就要為它設定一個獨立的taskAffinity屬性值。

如果設定了"singleTask"啟動模式的Activity不是在新的任務中啟動時,它會在已有的任務中檢視是否已經存在相應的Activity例項, 如果存在,就會把位於這個Activity例項上面的Activity全部結束掉,即最終這個Activity 例項會位於任務的Stack頂端中。

在一個任務棧中只有一個"singleTask"啟動模式的Activity存在。他的上面可以有其他的Activity。這點與singleInstance是有區別的。

singleInstance,回退棧中,只有這一個Activity,沒有其他Activity。

singleTop適合接收通知啟動的內容顯示頁面。

例如,某個新聞客戶端的新聞內容頁面,如果收到10個新聞推送,每次都開啟一個新聞內容頁面是很煩人的。

singleTask適合作為程式入口點。

例如瀏覽器的主介面。不管從多少個應用啟動瀏覽器,只會啟動主介面一次,其餘情況都會走onNewIntent,並且會清空主介面上面的其他頁面。

singleInstance應用場景:

鬧鈴的響鈴介面。 你以前設定了一個鬧鈴:上午6點。在上午5點58分,你啟動了鬧鈴設定介面,並按 Home 鍵回桌面;在上午5點59分時,你在微信和朋友聊天;在6點時,鬧鈴響了,並且彈出了一個對話方塊形式的 Activity(名為 AlarmAlertActivity) 提示你到6點了(這個 Activity 就是以 SingleInstance 載入模式開啟的),你按返回鍵,回到的是微信的聊天介面,這是因為 AlarmAlertActivity 所在的 Task 的棧只有他一個元素, 因此退出之後這個 Task 的棧空了。如果是以 SingleTask 開啟 AlarmAlertActivity,那麼當鬧鈴響了的時候,按返回鍵應該進入鬧鈴設定介面。

7. 說說Activity、Intent、Service 是什麼關係

他們都是 Android 開發中使用頻率最高的類。其中 Activity 和 Service 都是 Android 四大元件之一。他倆都是 Context 類的子類 ContextWrapper 的子類,因此他倆可以算是兄弟關係吧。不過兄弟倆各有各自的本領,Activity 負責使用者介面的顯示和互動,Service 負責後臺任務的處理。Activity 和 Service 之間可以通過 Intent 傳遞資料,因此 可以把 Intent 看作是通訊使者。

8. ActivityA跳轉ActivityB然後B按back返回A,各自的生命週期順序,A與B均不透明。

ActivityA跳轉到ActivityB

Activity A;onPause
Activity B;onCreate
Activity B;onStart
Activity B;onResume
Activity A;onStop

ActivityB返回ActivityA

Activity B;onPause
Activity A;onRestart
Activity A;onStart
Activity A;onResume
Activity B;onStop
Activity B;onDestroy

9. scheme跳轉協議

Android中的scheme是一種頁面內跳轉協議,通過定義自己的scheme協議,可以跳轉到app中的各個頁面

伺服器可以定製化告訴app跳轉哪個頁面

App可以通過跳轉到另一個App頁面

可以通過H5頁面跳轉頁面

10. 如何將一個Activity設定成視窗的樣式。

AndroidManifest中配置:

android:theme="@android:style/Theme.Dialog"

另外

android:theme="@android:style/Theme.Translucnt"

是設定透明。

11. Activity正常和異常情況下的生命週期

12. 通過Acitivty的xml標籤來改變任務棧的預設行為

  • 使用android:launchMode="standard|singleInstance|singleTask|singleTop"來控制Acivity任務棧。

    任務棧是一種後進先出的結構。位於棧頂的Activity處於焦點狀態,當按下back按鈕的時候,棧內的Activity會一個一個的出棧,並且呼叫其onDestory()方法。如果棧內沒有Activity,那麼系統就會回收這個棧,每個APP預設只有一個棧,以APP的包名來命名.

    • standard : 標準模式,每次啟動Activity都會建立一個新的Activity例項,並且將其壓入任務棧棧頂,而不管這個Activity是否已經存在。Activity的啟動三回撥(onCreate()->onStart()->onResume())都會執行。
    • singleTop : 棧頂複用模式.這種模式下,如果新Activity已經位於任務棧的棧頂,那麼此Activity不會被重新建立,所以它的啟動三回撥就不會執行,同時Activity的onNewIntent()方法會被回撥.如果Activity已經存在但是不在棧頂,那麼作用與standard模式一樣.
    • singleTask: 棧內複用模式.建立這樣的Activity的時候,系統會先確認它所需任務棧已經建立,否則先建立任務棧.然後放入Activity,如果棧中已經有一個Activity例項,那麼這個Activity就會被調到棧頂,onNewIntent(),並且singleTask會清理在當前Activity上面的所有Activity.(clear top)
    • singleInstance : 加強版的singleTask模式,這種模式的Activity只能單獨位於一個任務棧內,由於棧內複用的特性,後續請求均不會建立新的Activity,除非這個獨特的任務棧被系統銷燬了

Activity的堆疊管理以ActivityRecord為單位,所有的ActivityRecord都放在一個List裡面.可以認為一個ActivityRecord就是一個Activity棧

13. Activity 快取方法

有a、b兩個Activity,當從a進入b之後一段時間,可能系統會把a回收,這時候按back,執行的不是a的onRestart而是onCreate方法,a被重新建立一次,這是a中的臨時資料和狀態可能就丟失了。

可以用Activity中的onSaveInstanceState()回撥方法儲存臨時資料和狀態,這個方法一定會在活動被回收之前呼叫。方法中有一個Bundle引數,putString()、putInt()等方法需要傳入兩個引數,一個鍵一個值。資料儲存之後會在onCreate中恢復,onCreate也有一個Bundle型別的引數。

示例程式碼:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //這裡,當Acivity第一次被建立的時候為空
        //所以我們需要判斷一下
        if( savedInstanceState != null ){
            savedInstanceState.getString("anAnt");
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        outState.putString("anAnt","Android");

    }

一、onSaveInstanceState (Bundle outState)

當某個activity變得“容易”被系統銷燬時,該activity的onSaveInstanceState就會被執行,除非該activity是被使用者主動銷燬的,例如當用戶按BACK鍵的時候。

注意上面的雙引號,何為“容易”?言下之意就是該activity還沒有被銷燬,而僅僅是一種可能性。這種可能性有哪些?通過重寫一個activity的所有生命週期的onXXX方法,包括onSaveInstanceState和onRestoreInstanceState方法,我們可以清楚地知道當某個activity(假定為activity A)顯示在當前task的最上層時,其onSaveInstanceState方法會在什麼時候被執行,有這麼幾種情況:

1、當用戶按下HOME鍵時。

這是顯而易見的,系統不知道你按下HOME後要執行多少其他的程式,自然也不知道activity A是否會被銷燬,故系統會呼叫onSaveInstanceState,讓使用者有機會儲存某些非永久性的資料。以下幾種情況的分析都遵循該原則

2、長按HOME鍵,選擇執行其他的程式時。

3、按下電源按鍵(關閉螢幕顯示)時。

4、從activity A中啟動一個新的activity時。

5、螢幕方向切換時,例如從豎屏切換到橫屏時。(如果不指定configchange屬性) 在螢幕切換之前,系統會銷燬activity A,在螢幕切換之後系統又會自動地建立activity A,所以onSaveInstanceState一定會被執行

總而言之,onSaveInstanceState的呼叫遵循一個重要原則,即當系統“未經你許可”時銷燬了你的activity,則onSaveInstanceState會被系統呼叫,這是系統的責任,因為它必須要提供一個機會讓你儲存你的資料(當然你不儲存那就隨便你了)。另外,需要注意的幾點:

1.佈局中的每一個View預設實現了onSaveInstanceState()方法,這樣的話,這個UI的任何改變都會自動地儲存和在activity重新建立的時候自動地恢復。但是這種情況只有在你為這個UI提供了唯一的ID之後才起作用,如果沒有提供ID,app將不會儲存它的狀態。

2.由於預設的onSaveInstanceState()方法的實現幫助UI儲存它的狀態,所以如果你需要覆蓋這個方法去儲存額外的狀態資訊,你應該在執行任何程式碼之前都呼叫父類的onSaveInstanceState()方法(super.onSaveInstanceState())。 既然有現成的可用,那麼我們到底還要不要自己實現onSaveInstanceState()?這得看情況了,如果你自己的派生類中有變數影響到UI,或你程式的行為,當然就要把這個變數也儲存了,那麼就需要自己實現,否則就不需要。

3.由於onSaveInstanceState()方法呼叫的不確定性,你應該只使用這個方法去記錄activity的瞬間狀態(UI的狀態)。不應該用這個方法去儲存持久化資料。當用戶離開這個activity的時候應該在onPause()方法中儲存持久化資料(例如應該被儲存到資料庫中的資料)。

4.onSaveInstanceState()如果被呼叫,這個方法會在onStop()前被觸發,但系統並不保證是否在onPause()之前或者之後觸發。

二、onRestoreInstanceState (Bundle outState)

至於onRestoreInstanceState方法,需要注意的是,onSaveInstanceState方法和onRestoreInstanceState方法“不一定”是成對的被呼叫的,(本人注:我昨晚除錯時就發現原來不一定成對被呼叫的!)

onRestoreInstanceState被呼叫的前提是,activity A“確實”被系統銷燬了,而如果僅僅是停留在有這種可能性的情況下,則該方法不會被呼叫,例如,當正在顯示activity A的時候,使用者按下HOME鍵回到主介面,然後使用者緊接著又返回到activity A,這種情況下activity A一般不會因為記憶體的原因被系統銷燬,故activity A的onRestoreInstanceState方法不會被執行

另外,onRestoreInstanceState的bundle引數也會傳遞到onCreate方法中,你也可以選擇在onCreate方法中做資料還原。 還有onRestoreInstanceState在onstart之後執行。 至於這兩個函式的使用,給出示範程式碼(留意自定義程式碼在呼叫super的前或後):

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
        savedInstanceState.putBoolean("MyBoolean", true);
        savedInstanceState.putDouble("myDouble", 1.9);
        savedInstanceState.putInt("MyInt", 1);
        savedInstanceState.putString("MyString", "Welcome back to Android");
        // etc.
        super.onSaveInstanceState(savedInstanceState);
}

@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);

        boolean myBoolean = savedInstanceState.getBoolean("MyBoolean");
        double myDouble = savedInstanceState.getDouble("myDouble");
        int myInt = savedInstanceState.getInt("MyInt");
        String myString = savedInstanceState.getString("MyString");
}

14. Activity 生命週期

  • 啟動Activity: onCreate()—>onStart()—>onResume(),Activity進入執行狀態。
  • Activity退居後臺: 當前Activity轉到新的Activity介面或按Home鍵回到主屏: onPause()—>onStop(),進入停滯狀態。
  • Activity返回前臺: onRestart()—>onStart()—>onResume(),再次回到執行狀態。
  • Activity 退居後臺,且系統記憶體不足, 系統會殺死這個後臺狀態的Activity(此時這個Activity引用仍然處在任務棧中,只是這個時候引用指向的物件已經為null),若再次回到這個Activity,則會走onCreate()–>onStart()—>onResume()(將重新走一次Activity的初始化生命週期)
  • 鎖屏:onPause()->onStop()
  • 解鎖:onStart()->onResume()

15. onRestart 什麼時候呼叫?

1、按下 home 鍵執行,再次開啟這個 demo 執行;onRestart()--->onStart()--->onResume()三個方法。

2、點選介面的 btn,跳轉到另一個 Activity1,從 Activity1 返回,會執行;onRestart()--->onStart()--->onResume()三個方法

3、切換到其他的應用,從其他應用切換回來。onRestart()--->onStart()--->onResume()三個方法

16. Activity 與 Service 通訊的四種方式

【參考】http://itindex.net/detail/45126-android-service-activity

1、Binder
2、Intent
3、介面 Interface
4、Broadcast 廣播接收

17. Activity 之間的幾種通訊方式

【參考】https://blog.csdn.net/cyanchen666/article/details/81982562

1、Intent

2、藉助類的靜態變數

3、藉助全域性變數/Application

4、藉助外部工具

5、藉助 SharedPreference

6、使用 Android 資料庫 SQLite

7、赤裸裸的使用 File

8、Android 剪下板

9、藉助 Service

18. AlertDialog,Toast 對 Activity 生命週期的影響

【參考】:https://blog.csdn.net/cloud_castle/article/details/56011562

無論 Dialog 彈出覆蓋頁面,對 Activity 生命週期沒有影響,只有再啟動另外一個Activity 的時候才會進入 onPause 狀態,而不是想象中的被覆蓋或者不可見,同時通過AlertDialog 源 碼 或 者 Toast 源 碼 我 們 都 可 以 發 現 它 們 實 現 的 原 理 都 是windowmanager.addView();來新增的, 它們都是一個個 view ,因此不會對 activity 的生命週期有任何影響。

19. onCreate 中的 Bundle 有什麼用?

【參考】 https://blog.csdn.net/liubin8095/article/details/9328563

Activity 中有一個名稱叫 onCreate 的方法。該方法是在 Activity 建立時被系統呼叫,是一個 Activity 生命週期的開始。可是有一點容易被忽視,就是 onCreate 方法的引數saveInsanceState。一般的程式開發中,很少用到這個引數。onCreate 方法的完整定義如下:

public void onCreate(Bundle saveInsanceState){
  super.onCreate(saveInsanceState);
}

Bundle 型別的資料與 Map 型別的資料相似,都是以 key-value 的形式儲存資料的。從字面上看 saveInsanceState,是儲存例項狀態的。實際上,saveInsanceState 也就是儲存Activity 的狀態的。那麼,saveInsanceState 中的狀態資料是從何處而來的呢?下面我們介紹

Activity 的另一個方法 saveInsanceState。onsaveInsanceState 方法是用來儲存 Activity 的狀態的。當一個 Activity 在生命週期結束前,會呼叫該方法儲存狀態。

如下所示:

public void onSaveInsanceState(Bundle saveInsanceState){
  super.onSaveInsanceState(saveInsanceState);
}

在實際應用中,當一個 Activity 結束前,如果需要儲存狀態,就在 onsaveInsanceState 中,將狀態資料以 key-value 的形式放入到 saveInsanceState 中。這樣,當一個 Activity 被建立時,就能從 onCreate 的引數 saveInsanceState 中獲得狀態資料。狀態這個引數在實現應用中有很大的用途,比如:一個遊戲在退出前,儲存一下當前遊戲執行的狀態,當下次開啟時能接著上次的繼續玩下去。再比如:電子書程式,當一本小說被閱讀到第 199 頁後退出了(不管是記憶體不足還是使用者自動關閉程式),當下次開啟時,讀者可能已忘記了上次已閱讀到第幾頁了,但是,讀者想接著上次的讀下去。如果採用saveInstallState 引數,就很容易解決上述問題。

20. onSaveInstanceState() 與 onRestoreIntanceState()

Activity的 onSaveInstanceState() 和 onRestoreInstanceState()並不是生命週期方法,它們不同於 onCreate()、onPause()等生命週期方法,它們並不一定會被觸發。當應用遇到意外情況(如:記憶體不足、使用者直接按Home鍵)由系統銷燬一個Activity時,onSaveInstanceState() 會被呼叫。但是當用戶主動去銷燬一個Activity時,例如在應用中按返回鍵,onSaveInstanceState()就不會被呼叫。因為在這種情況下,使用者的行為決定了不需要儲存Activity的狀態。通常onSaveInstanceState()只適合用於儲存一些臨時性的狀態,而onPause()適合用於資料的持久化儲存。 在activity被殺掉之前呼叫儲存每個例項的狀態,以保證該狀態可以在onCreate(Bundle)或者onRestoreInstanceState(Bundle) (傳入的Bundle引數是由onSaveInstanceState封裝好的)中恢復。這個方法在一個activity被殺死前呼叫,當該activity在將來某個時刻回來時可以恢復其先前狀態。 例如,如果activity B啟用後位於activity A的前端,在某個時刻activity A因為系統回收資源的問題要被殺掉,A通過onSaveInstanceState將有機會儲存其使用者介面狀態,使得將來使用者返回到activity A時能通過onCreate(Bundle)或者onRestoreInstanceState(Bundle)恢復介面的狀態

深入理解

21.Activity 全面總結

22.5道刁鑽的 Activity 生命週期面試題