【轉】Android總結篇系列:Activity生命周期

来源:https://www.cnblogs.com/RYouHoo-923/archive/2018/01/17/8306108.html
-Advertisement-
Play Games

【轉】Android總結篇系列:Activity生命周期 Android官方文檔和其他不少資料都對Activity生命周期進行了詳細介紹,在結合資料和項目開發過程中遇到的問題,本文將對Activity生命周期進行一次總結。 Activity是由Activity棧進管理,當來到一個新的Activity ...


【轉】Android總結篇系列:Activity生命周期

Android官方文檔和其他不少資料都對Activity生命周期進行了詳細介紹,在結合資料和項目開發過程中遇到的問題,本文將對Activity生命周期進行一次總結。

Activity是由Activity棧進管理,當來到一個新的Activity後,此Activity將被加入到Activity棧頂,之前的Activity位於此Activity底部。Acitivity一般意義上有四種狀態:

1.當Activity位於棧頂時,此時正好處於屏幕最前方,此時處於運行狀態

2.當Activity失去了焦點但仍然對用於可見(如棧頂的Activity是透明的或者棧頂Activity並不是鋪滿整個手機屏幕),此時處於暫停狀態

3.當Activity被其他Activity完全遮擋,此時此Activity對用戶不可見,此時處於停止狀態

4.當Activity由於人為或系統原因(如低記憶體等)被銷毀,此時處於銷毀狀態;

在每個不同的狀態階段,Adnroid系統對Activity內相應的方法進行了回調。因此,我們在程式中寫Activity時,一般都是繼承Activity類並重寫相應的回調方法。

先貼一張來自官方文檔(http://developer.android.com/reference/android/app/Activity.html)的圖,相信大家都看到過。

 

圖中詳細給出了Activity整個生命周期的過程,以及在不同的狀態期間相應的回調方法。

圖中需要註意一下幾點:

1.Activity實例是由系統自動創建,併在不同的狀態期間回調相應的方法。一個最簡單的完整的Activity生命周期會按照如下順序回調:onCreate -> onStart -> onResume -> onPause -> onStop -> onDestroy。稱之為entire lifetime。

2.當執行onStart回調方法時,Activity開始被用戶所見(也就是說,onCreate時用戶是看不到此Activity的,那用戶看到的是哪個?當然是此Activity之前的那個Activity),一直到onStop之前,此階段Activity都是被用戶可見,稱之為visible lifetime。

3.當執行到onResume回調方法時,Activity可以響應用戶交互,一直到onPause方法之前,此階段Activity稱之為foreground lifetime。

在實際應用場景中,假設A Activity位於棧頂,此時用戶操作,從A Activity跳轉到B Activity。那麼對AB來說,具體會回調哪些生命周期中的方法呢?回調方法的具體回調順序又是怎麼樣的呢?

開始時,A被實例化,執行的回調有A:onCreate -> A:onStart -> A:onResume。

當用戶點擊A中按鈕來到B時,假設B全部遮擋住了A,將依次執行A:onPause -> B:onCreate -> B:onStart -> B:onResume -> A:onStop。

此時如果點擊Back鍵,將依次執行B:onPause -> A:onRestart -> A:onStart -> A:onResume -> B:onStop -> B:onDestroy。

至此,Activity棧中只有A。在Android中,有兩個按鍵在影響Activity生命周期這塊需要格外區分下,即Back鍵和Home鍵。我們先直接看下實驗結果:

此時如果按下Back鍵,系統返回到桌面,並依次執行A:onPause -> A:onStop -> A:onDestroy。

此時如果按下Home鍵(非長按),系統返回到桌面,並依次執行A:onPause -> A:onStop。由此可見,Back鍵和Home鍵主要區別在於是否會執行onDestroy。

此時如果長按Home鍵,不同手機可能彈出不同內容,Activity生命周期未發生變化(由小米2s測的,不知道其他手機是否會對Activity生命周期有影響)。

由於Android本身的特性,使得現在不少應用都沒有直接退出應用程式的功能,按照一般的邏輯,當Activity棧中有且只有一個Activity時,當按下Back鍵此Activity會執行onDestroy,那麼下次點擊此應用程圖標將從重新啟動,因此,當前不少應用程式都是採取如Home鍵的效果,當點擊了Back鍵,系統返回到桌面,然後點擊應用程式圖標,直接回到之前的Activity界面,這種效果是怎麼實現的呢?

通過重寫按下Back鍵的回調函數,轉成Home鍵的效果即可。

@Override
public void onBackPressed() {
    Intent home = new Intent(Intent.ACTION_MAIN);
    home.addCategory(Intent.CATEGORY_HOME);
    startActivity(home);
}

當然,此種方式通過Home鍵效果強行影響到Back鍵對Activity生命周期的影響。註意,此方法只是針對按Back鍵需要退回到桌面時的Activity且達到Home效果才重寫。

或者,為達到此類效果,Activity實際上提供了直接的方法。

1 activity.moveTaskToBack(true);

moveTaskToBack()此方法直接將當前Activity所在的Task移到後臺,同時保留activity順序和狀態。

 

在之前的項目開發過程中,當時遇到一個很奇怪的問題:手機上的“開發者選項”中有一個“不保留活動”的設置,當開啟此設置,手機上的設置提示是“用戶離開後即銷毀每個活動”,開啟後,對於其他的應用程式是從A Acticity到B Activity,然後Back鍵回到A,此時,其他應用程式只是先白屏(有可能黑屏等,取決於主題設置)一下,然後A開始可見,但是我的應用程式中出現的一個結果卻是直接返回到了桌面。一開始百思不得其解。最後終於定位出問題。首先,我們需要明確開啟此設置項後對Activity生命周期的影響。開啟此設置項後,當A到B時,假設B全部遮擋住了A,將依次執行A:onPause -> B:onCreate -> B:onStart -> B:onResume -> A:onStop -> A:onDestroy。是的,A在系統原本的生命周期回調中增加了onDestroy。此即“用戶離開後即銷毀每個活動”的含義。但此時需要註意的是,只要沒有認為的調用A的finish()方法,雖然A執行了onDestroy,但Activity棧中依然保留有A,此時B處於棧頂。那麼在B中按Back鍵回到A時,將依次執行:B:onPause -> A:onCreate -> A:onStart -> A:onResume -> B:onStop -> B:onDestroy。沒錯,A從onCreate開始執行了。此處也就解釋了為什麼A可能會出現白屏(或黑屏等)一下的原因了。

那麼為什麼我的應用程式會跟其他應用程式出現不一樣呢?最後定為出問題在於當時我的應用程式中為了做到完全退出應用程式效果,專門使用了一個Activity棧去維護Activity(當時是借鑒了網上的此類實現方案,現在想想,實在沒必要,且不說Android本身特性決定了沒必要通過如此方法去達到退出效果,僅僅是此方法本身也存在很大的問題,現在在網上依然能見到有不少文章說到應用程式退出可以使用此方法,哎。。),在onCreate中入棧,onDestroy出棧,調用瞭如下方法

1 // 結束Activity&從堆棧中移除
2 AppManager.getAppManager().finishActivity(this);

其中,AppManager中finishActivity函數具體定義是:

 1 /**
 2  * 結束指定的Activity
 3  */
 4 public void finishActivity(Activity activity) {
 5     if (activity != null) {
 6         activityStack.remove(activity);
 7         activity.finish();
 8         activity = null;
 9     }
10 }

至此,相信大家應該看出問題的所在了吧。

沒錯,問題在於執行了activity的finish()方法!! activity的finish()方法至少有兩個層面含義,1.將此Activity從Activity棧中移除,2.調用了此Activity的onDestroy方法。對於不開啟“不保留活動”的設置項,實際上也沒什麼影響,但是一旦開啟此設置,問題顯露無疑。開啟此此設置後,正常情況下離開A,即使執行了A的onDestroy,Activity棧中還是有A的,但是我這樣寫後,finish()方法一執行,Activity棧中就沒有A了,因此,當點擊Back鍵時,Activity棧中已經沒有此應用的任何Activity了,直接來到了手機桌面。

可能,有些人會說,我就是要通過此種方法想去完全退出應用程式,同時希望自己的Activity棧和系統中Activity棧保持一致,怎麼辦呢?

在此,可以通過如下改寫去實現:

 

/**
* 結束指定的Activity
 */
public void finishActivity(Activity activity) {
    if (activity != null) {
    // 為與系統Activity棧保持一致,且考慮到手機設置項里的"不保留活動"選項引起的Activity生命周期調用onDestroy()方法所帶來的問題,此處需要作出如下修正
    if(activity.isFinishing()){
        activityStack.remove(activity);
        //activity.finish();
        activity = null;
    }
    }
}

 

以此謹記!

-------------------------------------------------

此外,對於不同的啟動模式或Intent Flags或操作行為(如橫豎屏切換)等有可能會影響到Activity生命周期,此類問題將放在後續相關文章中進行總結。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • mysql備份還原 1.1 備份恢復-說明 運維工作的核心簡單概括就兩件事: 第一個:是保護公司的數據. 第二個:是讓網站能7*24小時提供服務(用戶體驗)。 1.1.1 備份簡介 1.2 mysqldump備份工具詳解 mysql原生自帶很好用的邏輯備份工具 1.2.1 mysqldump常用參數 ...
  • 進程啟動順序 Oracle Grid Infrastructure由OS初始化守護程式啟動 操作系統初始化守護進程(init)->Grid Infrastructure包裝腳本(init.ohasd)->Grid Infrastructure守護程式和進程(ohasd.bin,oraagent.bi ...
  • 概述 本篇我們將利用DMA一步一步實現SQL Server 的遷移。幫助大家理解現在的SQL Server與新版本的融合問題,同時需要我們做哪些操作來實現新版本的升級或者遷移。 SQL Server 遷移 一定要有一個準備好的計劃,我下麵列出了所有的遷移過程需要做的工作,如下列表: 步驟列表 序號 ...
  • 最近群里聊起秒殺和限流,我自己沒有做過類似應用,但是工作中遇到過更大的數據和併發。 於是提出了一個簡單的模型: var count = rds.inc(key); if(count > 1000) throw "已搶光!" 藉助Redis單線程模型,它的inc是安全的,確保每次加一,然後返回加一後的 ...
  • 工作中,經常會遇到將某個數據表的所有或大部份欄位讀取出來情況,比如說跨資料庫進行表更新或插入等。假如欄位名一個一個地敲的話,一是效率低,二是會有漏掉的情況。 針對此種情況,處理的方法有很多種,比如新建一個視圖,在裡面錄入SELECT * FROM 表名,系統會自動將星號改成欄位名(SQL SERVE ...
  • 查詢資料庫中的表及列,依資料庫自帶的函數,一條語句就可以搞定: ...
  • sqlserver: with Result as ( select SUM(F_DayValue) AS F_Value,F_ZZ_ttBuildID,F_EnergyItemCode from T_EC_EnergyItemDayResult where F_EnergyItemCode lik... ...
  • 〓資料庫的分類〓 資料庫通常分為層次式資料庫、網路式資料庫和關係式資料庫三種。而不同的資料庫是按不同的數據結構來聯繫和組織的。 而在當今的互聯網中,最常見的資料庫模型主要是兩種,即關係型資料庫和非關係型資料庫。 資料庫分類 〓關係型資料庫介紹〓 1、關係型資料庫的由來 雖然網狀資料庫和層次資料庫已經 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...