android lifeCycleOwner生命周期

一 Fragment中 viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) 什么時候執行?

讓我分析一下相關問題:

  1. 關于 onPause 時的數據更新:
viewLifecycleOwner.lifecycleScope.launch {viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {// 數據收集代碼}
}
  • repeatOnLifecycle(Lifecycle.State.STARTED) 意味著
    只在 Fragment 處于 STARTED 狀態(在 onStart 之后,onPause 之前)時才會收集數據
  • 當 Fragment 執行 onPause 時,數據收集會暫停,不會更新 UI
  • 這是正確的行為,因為不應該在后臺更新不可見的 UI
  1. 關于 onDestroyView 后的狀態恢復:
private val tempViewModel: TemperatureViewModel by viewModels()
private val fanViewModel: FanViewModel by viewModels()
private val sharedViewModel: SharedViewModel by activityViewModels()
  • viewModels() delegate 會在 Fragment 的生命周期內保持 ViewModel 實例
  • activityViewModels() delegate 會在 Activity 的生命周期內保持 ViewModel 實例
  • ViewModel 的狀態會在配置更改(如屏幕旋轉)時自動保持
  • 即使 Fragment 的 View 被銷毀,ViewModel 仍然存活,保持著最新狀態
  • 當 Fragment 重新創建 View 時,會使用同一個 ViewModel 實例,因此狀態自動恢復
  1. 數據恢復流程:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)initView()collectUiState() // 重新開始收集數據
}
  • 當 Fragment 重新創建 View 時,會重新調用 collectUiState()
  • ViewModel 中的 StateFlow/Flow 會發送最新狀態
  • UI 會立即更新到最新狀態

這種實現方式是合理的,因為:

  1. 遵循了 Android 生命周期安全原則
  2. 避免了在后臺不必要的 UI 更新
  3. 保證了狀態的可靠性和一致性
  4. 有效處理了配置更改場景

二 為什么viewModel在view銷毀,仍能存活,保存著ui狀態?

delegate 確實是代理的含義。讓我解釋 viewModels() delegate 的工作原理:

  1. Delegate 機制:
private val viewModel: MyViewModel by viewModels()
  • by 關鍵字表示使用 Kotlin 的屬性代理
  • viewModels() 返回一個 ViewModelLazy 對象
  • 代理負責處理 ViewModel 的實例化和獲取
  1. ViewModelLazy 工作原理:
class ViewModelLazy<VM : ViewModel>(private val viewModelClass: KClass<VM>,private val storeProducer: () -> ViewModelStore,private val factoryProducer: () -> ViewModelProvider.Factory
) : Lazy<VM> {private var cached: VM? = nulloverride val value: VMget() {val viewModel = cachedreturn if (viewModel == null) {val factory = factoryProducer()val store = storeProducer()ViewModelProvider(store, factory).get(viewModelClass.java).also {cached = it}} else {viewModel}}
}
  1. ViewModel 存活原理:
  • Fragment 持有對 ViewModelStore 的引用
  • ViewModelStore 是一個簡單的 HashMap,用于存儲 ViewModel 實例
  • ViewModelStore 與 Fragment 的生命周期解耦,不隨 View 的銷毀而銷毀
  • 只有在 Fragment 真正被銷毀時(如 Activity 被銷毀),ViewModelStore 才會清理
  1. 配置更改時的行為:
Fragment 重建 ─→ ViewModelStore 保持存活
↓                    ↓
新的 View        原有 ViewModel 實例
↓                    ↓
重新綁定數據     狀態保持不變

優點:

  1. 延遲初始化 - 只在首次訪問時創建 ViewModel
  2. 生命周期安全 - 自動處理 ViewModel 的創建和清理
  3. 狀態保持 - 在配置更改時保存數據
  4. 內存管理 - 適時清理不需要的 ViewModel 實例

這就是為什么即使在 View 銷毀或屏幕旋轉時,ViewModel 仍能保持狀態的技術原理。

三 android中 activity和viewModel生命周期的區別是什么

在 Android 的架構中,ActivityViewModel 有著不同的生命周期管理機制,這是 MVVM 架構中實現 UI 狀態持久化和解耦的核心基礎


? 一、Activity 與 ViewModel 生命周期的區別

對象生命周期誰管理生命周期范圍銷毀時機
Activity系統管理(與 UI 生命周期強綁定)短暫(屏幕旋轉、返回鍵等都會銷毀)屏幕旋轉、按返回鍵、系統回收
ViewModelViewModelStore 管理(由 ViewModelProvider 創建)綁定到 Activity / Fragment 的生命周期所依附的 Activity Fragment 銷毀后才銷毀

? 二、為什么 Activity 銷毀了 ViewModel 才銷毀?

因為 ViewModel 是為“配置更改下的數據持久化”設計的組件,Android 會:

  • 在屏幕旋轉(或語言切換等配置更改)時,銷毀舊的 Activity 實例,創建一個新的。
  • 但 ViewModel 被托管在 ViewModelStore 中,不跟隨 Activity 的配置變更銷毀。
  • 直到 Activity 真正 finish 或被系統 kill,ViewModel 才銷毀。

👉 這意味著:

屏幕旋轉只是臨時銷毀了 UI,但 ViewModel 仍然活著。


? 三、為什么 ViewModel 可以持久化 UI 狀態?

因為 ViewModel 的職責就是存儲并管理界面相關的數據,且生命周期長于 Activity:

  • 它存在于 ActivityFragment 的作用域內,但 不會因配置更改而銷毀
  • 所以可以在 ViewModel 中存儲 UI 狀態(如輸入框內容、選中項、滾動位置等)。
  • 當新的 Activity 創建時,通過同一個 ViewModelProvider 獲取原有 ViewModel,數據依然存在!

🎯 舉個例子:

class MyViewModel : ViewModel() {val userName = MutableLiveData<String>()
}

在 Activity 中使用:

val viewModel = ViewModelProvider(this)[MyViewModel::class.java]viewModel.userName.observe(this) {// 更新 UI
}

即使屏幕旋轉,Activity 重建了,但 viewModel 是同一個,userName 依舊保留!


? 四、深入原理:ViewModel 如何“活得更久”?

  1. Android Framework 在配置變化時,會:
  • 暫時保存 ViewModelStoreSavedStateRegistry
  • 銷毀舊 Activity 并創建新 Activity。
  • 將舊的 ViewModelStore 重新附加給新 Activity。
  1. ViewModel 保存在 ViewModelStore,而不是在 Activity 實例里。

所以:

Activity 重建 ≠ ViewModel 重建

? 五、ViewModel 銷毀時機總結:

  • Activity.finish() 或被系統 kill,才會銷毀 ViewModel。
  • Fragment 的 ViewModel 也可以作用域更長(如綁定到父 Activity)。
  • ViewModelonCleared() 方法會在真正銷毀時調用,可釋放資源。

? 六、補充:如果希望屏幕旋轉后也保持 UI 狀態,有三種方式對比:

方法是否推薦說明
onSaveInstanceState()? 可選保存輕量級 UI 狀態(如文本、位置)
ViewModel? 推薦保存更大或復雜的數據結構,且與 UI 解耦
Room/DB? 長期存儲跨進程或跨 Activity 的持久狀態

四 viewModel什么時候銷毀?

屏幕旋轉時,Activity 的確會被銷毀,但這并不等價于我們手動調用的 Activity.finish() 方法。這兩者在 Android Framework 中有重要區別。


? 關鍵理解:屏幕旋轉導致的是“配置更改銷毀”,不是調用 finish()

當屏幕旋轉發生時:

系統會執行:
1. 銷毀舊的 Activity 實例(onDestroy() 被調用)
2. 創建一個新的 Activity 實例(走 onCreate())

但這 并不是調用了代碼中的 finish() 方法,而是 Android 框架內部處理配置變化的一個機制。它不會觸發真正的「完全生命周期終結」,而是帶有保留機制的銷毀。


? 為什么 ViewModel 不被銷毀?

背后的機制是:

  • 每個 Activity 背后都有一個 ViewModelStore
  • 當因配置變化(如旋轉)導致 Activity 被銷毀時,Android 會臨時保存舊的 ViewModelStore
  • 然后,新 Activity 被創建時,從保存的 ViewModelStoreOwner 重新獲取舊的 ViewModel 實例

這個行為是由 ViewModelProviderSavedStateViewModelFactory 等底層機制共同支持的。


? 更形象地理解:

假設旋轉屏幕時發生了如下變化:

舊的 Activity(A1):
ViewModelStore 里存著 MyViewModel旋轉后創建新的 Activity(A2):
系統會把 A1 的 ViewModelStore 傳遞給 A2A2 調用 ViewModelProvider(this)[MyViewModel::class.java] 時,
得到的是 A1 中的同一個 ViewModel 實例

因此:

  • ViewModel 沒有被銷毀
  • ViewModel 里的數據依然存在。
  • 看到 UI 狀態得以“保留”。

? 那 ViewModel 什么情況下才會銷毀?

ViewModel 生命周期取決于它所綁定的 ViewModelStoreOwner,比如 ActivityFragment

情況ViewModel 會銷毀嗎?
屏幕旋轉(配置更改)? 不會
手動調用 finish()? 會
用戶點擊返回鍵退出 Activity? 會
系統因資源不足殺死進程? 會
Fragment detach 且不復用? 會

? 所以總結:

  • 屏幕旋轉 ≠ finish(),雖然 onDestroy() 會被調用,但屬于“可恢復銷毀”。
  • ViewModel 被設計為適應這種情況,并保留數據,避免 UI 狀態丟失。
  • ViewModel 的生命周期由 ViewModelStore 控制,不直接綁定 Activity 的內存生命周期

五 Fragment 關聯的 ViewModel 的銷毀時機。

1. Fragment ViewModel 的兩種作用域

Fragment 可以使用兩種方式創建 ViewModel:

// 1. Fragment 作用域的 ViewModel
private val fragmentViewModel: MyViewModel by viewModels()// 2. Activity 作用域的 ViewModel
private val activityViewModel: SharedViewModel by activityViewModels()

2. Fragment作用域 ViewModel 的銷毀時機

Fragment 作用域的 ViewModel 在以下情況會銷毀:

class MyFragment : Fragment() {private val viewModel by viewModels<MyViewModel>()override fun onDestroy() {super.onDestroy()// Fragment 真正銷毀時,ViewModel 也會銷毀}
}

銷毀場景:

  1. Fragment 被移除且不再復用
  2. 宿主 Activity 被銷毀(非配置變更導致的銷毀)
  3. Fragment detach 且不會再次 attach

不會銷毀的場景

  1. Fragment 視圖銷毀(onDestroyView)
  2. 屏幕旋轉等配置變更
  3. Fragment 被替換但加入了返回棧

3. Activity作用域 ViewModel 的銷毀時機

class MyFragment : Fragment() {private val sharedViewModel by activityViewModels<SharedViewModel>()// Activity 銷毀時才會銷毀,Fragment 的生命周期變化不影響
}

銷毀場景:

  1. 宿主 Activity finish
  2. 系統回收 Activity
  3. 用戶按返回鍵退出 Activity

4. 實際示例

class MyFragment : Fragment() {// Fragment 作用域 ViewModelprivate val fragmentViewModel by viewModels<MyViewModel>()// Activity 作用域 ViewModelprivate val sharedViewModel by activityViewModels<SharedViewModel>()override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {// Fragment view 創建return inflater.inflate(R.layout.fragment_my, container, false)}override fun onDestroyView() {super.onDestroyView()// View 銷毀,ViewModel 仍然存活}override fun onDestroy() {super.onDestroy()// Fragment 銷毀,fragmentViewModel 銷毀// 但 sharedViewModel 仍然存活}
}

5. ViewModel 清理機制

class MyViewModel : ViewModel() {override fun onCleared() {super.onCleared()// ViewModel 銷毀時執行清理工作// 取消協程// 釋放資源}
}

6. 注意事項

  1. 防止內存泄漏
class MyViewModel : ViewModel() {private val coroutineScope = CoroutineScope(Dispatchers.Main + Job())override fun onCleared() {coroutineScope.cancel() // 清理協程super.onCleared()}
}
  1. 視圖引用
class MyViewModel : ViewModel() {// 錯誤:不要持有 View 引用private lateinit var binding: FragmentBinding// 正確:使用 LiveData/StateFlow 通知 UIprivate val _state = MutableStateFlow<UiState>()val state = _state.asStateFlow()
}

7. 總結

Fragment ViewModel 的銷毀時機取決于:

  1. 使用的作用域(Fragment 還是 Activity)
  2. Fragment/Activity 的真實生命周期結束
  3. 非配置變更導致的銷毀

理解這些銷毀時機對于:

  • 正確管理資源
  • 避免內存泄漏
  • 實現合適的數據共享
    非常重要。

六 判斷Fragment是否被銷毀

Fragment 調用 onDestroy() 不一定意味著 Fragment 被永久移除。讓我詳細解釋:

Fragment 的幾種銷毀情況

  1. 配置變更時的臨時銷毀:
class MyFragment : Fragment() {private val viewModel by viewModels()override fun onDestroy() {super.onDestroy()// 配置變更時會調用,但 ViewModel 不會銷毀}
}
  1. 真正的永久銷毀:
// Activity 中
supportFragmentManager
.beginTransaction()
.remove(fragment)  // 移除 Fragment
.commit()
  1. 加入返回棧的銷毀:
supportFragmentManager
.beginTransaction()
.replace(R.id.container, NewFragment())
.addToBackStack(null)  // Fragment 被替換但可返回
.commit()

判斷是否真正銷毀的方式

class MyFragment : Fragment() {override fun onDestroy() {super.onDestroy()when {// 1. 檢查是否是配置變更activity?.isChangingConfigurations == true -> {// ViewModel 不會銷毀}// 2. 檢查是否在返回棧中isRemoving && !requireActivity().isFinishing -> {if (fragmentManager?.backStackEntryCount ?: 0 > 0) {// Fragment 在返回棧中,ViewModel 不會銷毀} else {// Fragment 被永久移除,ViewModel 會銷毀}}// 3. Activity 正在銷毀requireActivity().isFinishing -> {// Fragment 和 ViewModel 都會銷毀}}}
}

Fragment ViewModel 的銷毀時機

class MyFragment : Fragment() {private val viewModel by viewModels()// ViewModel 會在以下情況銷毀:// 1. Fragment 被永久移除fragmentManager.beginTransaction().remove(this).commit()// 2. 宿主 Activity 被銷毀activity?.finish()// 3. Fragment detach 且不會重新 attachfragmentManager.beginTransaction().detach(this).commit()
}

關鍵判斷條件

override fun onDestroy() {super.onDestroy()val isReallyDestroying = when {// 配置變更不算真正銷毀activity?.isChangingConfigurations == true -> false// Fragment 被移除且不在返回棧中isRemoving && fragmentManager?.backStackEntryCount == 0 -> true// Activity 結束activity?.isFinishing == true -> trueelse -> false}if (isReallyDestroying) {// ViewModel 會在這種情況下銷毀}
}

總結:

  • onDestroy() 被調用不等于 Fragment 被永久移除
  • 需要考慮配置變更、返回棧和 Activity 狀態
  • ViewModel 只在 Fragment 真正不再使用時才銷毀

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/908247.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/908247.shtml
英文地址,請注明出處:http://en.pswp.cn/news/908247.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Liunx進程替換

文章目錄 1.進程替換2.替換過程3.替換函數exec3.1命名解釋 4.細說6個exe函數execl函數execvexeclp、execvpexecle、execve 1.進程替換 fork&#xff08;&#xff09;函數在創建子進程后&#xff0c;子進程如果想要執行一個新的程序&#xff0c;就可以使用進程的程序替換來完成…

【華為云Astro-服務編排】服務編排中圖元的使用與配置

目錄 子服務編排圖元 子服務編排圖元的作用 如何使用子服務編排圖元 腳本圖元 腳本圖元的作用 如何使用腳本圖元 記錄創建圖元 記錄創建圖元的作用 如何使用記錄創建圖元 記錄刪除圖元 記錄刪除圖元的作用 如何使用記錄刪除圖元 記錄查詢圖元 記錄查詢圖元的作用…

SQL Server相關的sql語句

目錄 一、數據定義語言&#xff08;DDL&#xff09;1. 創建數據庫2. 修改數據庫3. 刪除數據庫4. 創建表5. 修改表結構6. 刪除表 二、數據操作語言&#xff08;DML&#xff09;1. 插入數據2. 更新數據3. 刪除數據 三、數據查詢語言&#xff08;DQL&#xff09;1. 基礎查詢2. 去重…

【Hot 100】55. 跳躍游戲

目錄 引言跳躍游戲我的解題 &#x1f64b;?♂? 作者&#xff1a;海碼007&#x1f4dc; 專欄&#xff1a;算法專欄&#x1f4a5; 標題&#xff1a;【Hot 100】55. 跳躍游戲?? 寄語&#xff1a;書到用時方恨少&#xff0c;事非經過不知難&#xff01; 引言 跳躍游戲 &#x…

基于51單片機的車內防窒息檢測報警系統

目錄 具體實現功能 設計介紹 資料內容 全部內容 資料獲取 具體實現功能 具體實現功能&#xff1a; &#xff08;1&#xff09;檢測車內溫度及二氧化碳濃度并用lcd1602實時顯示。 &#xff08;2&#xff09;當人體紅外傳感器檢測到車內有人&#xff0c;且溫度或二氧化碳濃度…

關于智能體API參考接口

關于智能體在Flask的源碼&#xff1a;請求體(在payload里的是請求體)、請求頭&#xff08;在headers里的i局勢請求頭&#xff09;。 我的例子&#xff1a; 我的疑問&#xff1a;為什么沒按Coze官方API文檔格式&#xff0c;在Apifox里發POST請求卻能收到回復&#xff1f; 1. 你…

Excel 批量下載PDF、批量下載考勤圖片——仙盟創夢IDE

在辦公場景中&#xff0c;借助應用軟件實現 Excel 批量處理考勤圖片、電子文檔與 PDF&#xff0c;具有諸多顯著優勢。 從考勤圖片處理來看&#xff0c;通過 Excel 批量操作&#xff0c;能快速提取圖片中的考勤信息&#xff0c;如員工打卡時間、面部識別數據等&#xff0c;節省…

Apache Doris + MCP:Agent 時代的實時數據分析底座

一、Apache Doris&#xff1a;面向 Agent 時代的智能數據平臺 當我們談論 2025 年時&#xff0c;業界普遍認為這將是"Agent 革命年"&#xff08;Agentic Revolution&#xff09;的開端。與傳統的人機交互模式不同&#xff0c;AI Agent 作為一個全新的"用戶角色…

能不能用string接收數據庫的datetime類型字段

在Java中使用String類型通過MyBatis接收MySQL的datetime類型字段時&#xff0c;?可以正常工作&#xff0c;但需注意格式和潛在問題。以下是關鍵點&#xff1a; 1. ?直接轉換是可行的? MySQL的datetime字段&#xff08;如 2023-10-05 12:34:56&#xff09;會被MyBatis自動轉…

【Python訓練營打卡】day44 @浙大疏錦行

DAY 44 預訓練模型 知識點回顧&#xff1a; 1. 預訓練的概念 2. 常見的分類預訓練模型 3. 圖像預訓練模型的發展史 4. 預訓練的策略 5. 預訓練代碼實戰&#xff1a;resnet18 作業&#xff1a; 1. 嘗試在cifar10對比如下其他的預訓練模型&#xff0c;觀察差異&#xff0c;…

MySQL中關于事務和鎖的常見執行命令整理包括版本區別

MySQL中關于事務和鎖的常見執行命令實例整理&#xff0c;并標注了不同版本下的區別&#xff08;如MySQL 8.0與舊版本的差異&#xff09;&#xff1a; 一、事務相關命令 1. 事務控制 命令描述版本差異START TRANSACTION; 或 BEGIN;顯式開啟事務通用語法&#xff0c;無版本差異…

PyTorch-Transforms的使用(二)

對圖像進行處理 安裝open cv ctrlP 看用法 ToTensor的使用 常見的Transforms 歸一化的圖片 兩個長度為三的數組&#xff0c;分別表示三個通道的平均值和標準差 Resize&#xff08;&#xff09; Compose&#xff08;&#xff09; 合并執行功能&#xff0c;輸入進去一個列表&a…

vscode實用配置

前端開發安裝插件&#xff1a; 1.可以更好看的顯示文件圖標 2.用戶快速打開文件 使用步驟&#xff1a;在html文件下右鍵點擊 open with live server 即可 刷力扣&#xff1a; 安裝這個插件 還需要安裝node.js即可

Day130 | 靈神 | 回溯算法 | 子集型 電話號碼的字母組合

Day130 | 靈神 | 回溯算法 | 子集型 電話號碼的字母組合 17.電話號碼的字母組合 17. 電話號碼的字母組合 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 筆者用index代替i&#xff0c;這里的index其實就是digits數組的下標 按照靈神的回溯三問&#xff0c;那就…

深入理解JavaScript設計模式之閉包與高階函數

前言小序 一場失敗面試 2023年的某一天&#xff0c;一場讓我印象深刻的面試&#xff1a; 面試官&#xff1a; “你了解閉包嗎&#xff1f;請說一下你對閉包的理解。” 我自信滿滿地答道&#xff1a; “閉包就是函數里面套函數&#xff0c;里面的函數可以訪問外部函數的變量。…

使用 Spring Boot 3.3 和 JdbcTemplate 操作 MySQL 數據庫

在現代的 Java 應用開發中&#xff0c;Spring Boot 提供了強大的工具來簡化數據庫操作。JdbcTemplate 是 Spring 提供的一個核心類&#xff0c;用于簡化 JDBC 操作&#xff0c;減少樣板代碼。本文將介紹如何在 Spring Boot 3.3 項目中使用 JdbcTemplate 來操作 MySQL 數據庫&am…

如何做好一份技術文檔?(下篇)

如何做好一份技術文檔&#xff1f;&#xff08;下篇&#xff09; 下篇&#xff1a;文檔體驗的極致優化 ——從可用性到愉悅性的跨越 文檔用戶體驗地圖 新手路徑 專家路徑 [安裝] → [配置] → [示例] [API] → [參數] → [源碼] │ ▲ …

Windows 12確認沒了,Win11 重心偏移修Bug

微軟悄然擱置了傳說中的Windows 12開發計劃&#xff0c;轉身將精力投入到Windows 11的持續進化中。今年秋季的主角已經確定——Windows 11 25H2&#xff0c;它將于9月或10月間與我們正式見面。 與去年24H2的大規模更新不同&#xff0c;25H2更像是場精心策劃的“功能解鎖”。微軟…

JavaScript中的正則表達式:文本處理的瑞士軍刀

JavaScript中的正則表達式&#xff1a;文本處理的瑞士軍刀 在編程世界中&#xff0c;正則表達式&#xff08;Regular Expression&#xff0c;簡稱RegExp&#xff09;被譽為“文本處理的瑞士軍刀”。它能夠高效地完成字符串匹配、替換、提取和驗證等任務。無論是前端開發中的表…

基于LEAP模型在能源環境發展、碳排放建模預測及分析中實踐應用

在國家“3060”碳達峰碳中和的政策背景下&#xff0c;如何尋求經濟-能源-環境的平衡有效發展是國家、省份、城市及園區等不同級別經濟體的重要課題。根據國家政策、當地能源結構、能源技術發展水平以及相關碳排放指標制定合理有效的低碳能源發展規劃需要以科學準確的能源環境發…