Android的LiveData

LiveData 是一種可觀察的數據存儲器類。與常規的可觀察類不同,LiveData 具有生命周期感知能力,意指它遵循其他應用組件(如 activity、fragment 或 service)的生命周期。這種感知能力可確保 LiveData 僅更新處于活躍生命周期狀態的應用組件觀察者

若觀察者(Observer)的生命周期處于STARTEDRESUMED狀態,則LiveData會認為該Observer處于活躍狀態。LiveData只會將更新通知給活躍的Observer。

您可以注冊與實現?LifecycleOwner?接口的對象配對的觀察者。有了這種關系,當相應的?Lifecycle?對象的狀態變為?DESTROYED?時,便可移除此觀察者。這對于 activity 和 fragment 特別有用,因為它們可以放心地觀察?LiveData?對象,而不必擔心泄露(當 activity 和 fragment 的生命周期被銷毀時,系統會立即退訂它們)。

使用LiveData的優勢

確保界面符合數據狀態:LiveData遵循觀察者模式。當底層數據發生變化,LiveData會通知Observer對象,此時我們可以寫入邏輯,以在Observer中更新界面。這樣一來,我們就不用每次在數據發生變化時更新界面,因為Observer會完成這一內容;

不會發生內存泄漏:Observer綁定到LifeCycle對象,并在其關聯的生命周期結束后自動清理,這一點與ViewModel類似;

不會因為Activity停止而導致崩潰:若Observer的生命周期處于非活躍狀態(如返回對戰的activity),它就不會接受LiveData事件;

不需要手動處理生命周期:界面組件只是觀察相關數據,不會停止或恢復觀察。LiveData 將自動管理所有這些操作,因為它在觀察時可以感知相關的生命周期狀態變化;

使用LiveData對象

當更新存儲在LiveData對象中的值時,它會觸發所有已注冊的Observer(只要它所附加的Life cycleOwner處于活躍狀態)。

創建

LiveData對象通常存儲在ViewModel對象中,并可以使用getter方法訪問:

class NameViewModel : ViewModel() {// LiveData可用于任何類型的數據,此處創建一個String類型的LiveData對象val currentName: MutableLiveData<String> by lazy {//使用lazy懶加載,當需要使用再創建MutableLiveData<String>()}// ViewModel的剩余部分...
}

存儲在ViewModel中、而不是activity或fragment的原因是:

  • 避免activity和fragment過于龐大。我們使用MVVM架構的原因之一,就是為了使這些界面控制器只負責顯示數據,而不存儲數據;
  • 將LiveData實例與特定的activity或fragment實例分離開,使得LiveData對象在配置更改后仍然存在。

觀察

大多數時候,從組件onCreate方法中開始觀察LiveData對象,以確保系統不會從onResume方法中進行冗余調用,并確保activity或fragment變為活躍狀態后具有可以立即顯示的數據。一旦組件處于STARTED狀態,就會從它觀察的LiveData接受最新的值。

另外,除了LiveData在發生數據更改時會發送更新,Observer從非活躍狀態變為活躍狀態時也會收到更新。但是,如果Observer第二次發生這樣的狀態改變,則只有上次的改變會收到更新。

class NameActivity : AppCompatActivity() {private val model: NameViewModel by viewModels()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// 其他初始化activity的內容...// 創建觀察ui更新的observerval nameObserver = Observer<String> { newName ->// 更新ui,此處是一個TextViewnameTextView.text = newName}// 觀察LiveData, 將此activity作為LifecycleOwner和observermodel.currentName.observe(this, nameObserver)}
}

我們也可以簡寫這一部份:

class NameActivity : AppCompatActivity() {private val model: NameViewModel by viewModels()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// 其他初始化activity的內容...// 簡寫nameTextView.text = model.currentName.observeAsState()}
}

在傳遞nameObserver參數的情況下調用observe方法后,系統會立即調用onChanged方法,從而提供mCurrentName中存儲的最新值。若LiveData對象上為在mCurrentName中設置值,系統不會調用onChanged方法。

更新

LiveData沒有公開可用的方法來更新存儲的數據。如果需要修改存儲在LiveData對象中的值,需要重寫MutableLiveData中的setValue方法或postValue方法。

通常情況下會在ViewModel中使用MutableLiveData,然后ViewModel只會向觀察者公開不可變的LiveData對象。設置觀察者關系之后,我們就可以更新LiveData對象的值:

button.setOnClickListener {val anotherName = "John Doe"model.currentName.setValue(anotherName)
}

在主線程中我們使用setValue方法更新數據,而在工作器線程中,我們可以改用postValue方法來更新Livedata對象。

擴展LiveData?

如果觀察者的生命周期處于STARTED或RESUMED狀態,則LiveData會認為該觀察者處于活躍狀態,以下是擴展LiveData類的例子:

//價格監聽器
class StockLiveData(symbol: String) : LiveData<BigDecimal>() {private val stockManager = StockManager(symbol)private val listener = { price: BigDecimal ->value = price}//當LiveData對象具有活躍觀察者時,會調用此方法override fun onActive() {//從此方法開始觀察股價更新stockManager.requestPriceUpdates(listener)}//當LiveData對象沒有活躍觀察者時,會調用此方法override fun onInactive() {//斷開StockManager服務stockManager.removeUpdates(listener)}
}

接下來我們使用重寫后的StockLiveData類:

public class MyFragment : Fragment() {override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)val myPriceListener: LiveData<BigDecimal> = ...myPriceListener.observe(viewLifecycleOwner, Observer<BigDecimal> { price: BigDecimal? ->// Update the UI.})}
}

組件如activity、fragment在初始化時構建了自己的LifecycleOwener。此處的observe方法將與Fragment視圖關聯的LifecycleOwner作為第一個參數傳遞,這樣做表示此觀察者已綁定到與其所有者關聯的Lifecycle對象(即組件,在此處是MyFragment),這意味著;

  • 如果Lifecycle對象未處于活躍狀態,即使值發生更改,也不會調用觀察者;
  • 銷毀Lifecycle對象后,會自動移除觀察者。

同時LiveData對象具有生命周期感知能力,意味著我們可以在多個activity、fragment和service之間共享這些對象。

我們也可以將StockLiveData實現為一個單例(companion object):

class StockLiveData(symbol: String) : LiveData<BigDecimal>() {private val stockManager: StockManager = StockManager(symbol)private val listener = { price: BigDecimal ->value = price}override fun onActive() {stockManager.requestPriceUpdates(listener)}override fun onInactive() {stockManager.removeUpdates(listener)}companion object {private lateinit var sInstance: StockLiveData@MainThreadfun get(symbol: String): StockLiveData {sInstance = if (::sInstance.isInitialized) sInstance else StockLiveData(symbol)return sInstance}}
}

為什么使用了單例?以StockLiveData為例,單例的好處是在使用時不需要再創建一個StockLiveData的實例,而是直接引用它的方法:

class MyFragment : Fragment() {override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)StockLiveData.get(symbol).observe(viewLifecycleOwner, Observer<BigDecimal> { price: BigDecimal? ->// Update the UI.})}

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

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

相關文章

ChatGPT在醫學領域的應用與前景

標題&#xff1a; ChatGPT在醫學領域的應用與前景 正文&#xff1a; 隨著人工智能技術的不斷進步&#xff0c;ChatGPT等語言模型在醫學領域的應用逐漸深入&#xff0c;展現出其巨大的潛力和廣闊的發展前景。作為一個高級的自然語言處理工具&#xff0c;ChatGPT能夠理解和生成…

WPF 開發調試比較:Visual Studio 原生和Snoop調試控制臺

文章目錄 前言運行環境簡單的WPF代碼實現一個簡單的ListBoxVisual Studio自帶代碼調試熱重置功能測試實時可視化樹查找窗口元素顯示屬性 Snoop調試使用Snoop簡單使用調試控制臺元素追蹤結構樹Visual/可視化結構樹Logical/本地代碼可視化樹AutoMation/自動識別結構樹 WPF元素控制…

基于springboot+vue的房屋租賃管理系統(前后端分離)

博主主頁&#xff1a;貓頭鷹源碼 博主簡介&#xff1a;Java領域優質創作者、CSDN博客專家、阿里云專家博主、公司架構師、全網粉絲5萬、專注Java技術領域和畢業設計項目實戰&#xff0c;歡迎高校老師\講師\同行交流合作 ?主要內容&#xff1a;畢業設計(Javaweb項目|小程序|Pyt…

【OpenAI官方課程】第四課:ChatGPT文本推斷Summarizing

歡迎來到ChatGPT 開發人員提示工程課程&#xff08;ChatGPT Prompt Engineering for Developers&#xff09;&#xff01;本課程將教您如何通過OpenAI API有效地利用大型語言模型&#xff08;LLM&#xff09;來創建強大的應用程序。 本課程由OpenAI 的Isa Fulford和 DeepLearn…

手拉手Vite+Vue3+TinyVue+Echarts+TailwindCSS

技術棧springboot3hutool-alloshi-coreVue3viteTinyVueEchartsTailwindCSS軟件版本IDEAIntelliJ IDEA 2022.2.1JDK17Spring Boot3.1hutool-all5.8.18oshi-core6.4.1Vue35.0.10vite5.0.10axios1.6.7echarts5.4.3 ECharts是一個使用 JavaScript 實現的開源可視化庫&#xff0c;可…

快速搭建ARM64實驗平臺(QEMU虛擬機+Debian)

文章目錄 前言一、實驗平臺介紹二、安裝步驟2.1 安裝工具2.2 下載倉庫2.3 編譯內核并制作根文件系統2.4 運行剛才編譯好的ARM64版本的Debian系統2.5 在線安裝軟件包2.6 在QEMU虛擬機和主機之間共享文件 三、單步調試ARM64 Linux內核參考資料 前言 最近翻閱笨叔的《奔跑吧Linux…

go-zero微服務入門教程

go-zero微服務入門教程 本教程主要模擬實現用戶注冊和用戶信息查詢兩個接口。 準備工作 安裝基礎環境 安裝etcd&#xff0c; mysql&#xff0c;redis&#xff0c;建議采用docker安裝。 MySQL安裝好之后&#xff0c;新建數據庫dsms_admin&#xff0c;并新建表sys_user&#…

【Git】 刪除遠程分支

Git 刪除遠程分支有以下幾種方法 服務端UI工具 Git 的服務端圖形化工具主要是 web 端。常用的有 GitHub、Gitea、Gutlab 等。 這些工具都提供了分支管理&#xff0c;可以直接在各服務端找到相關功能&#xff0c;謹慎刪除。 客戶端UI工具 Git 擁有諸多客戶端 UI 工具&#x…

詳細分析Python中的unittest測試框架

目錄 1. 基本知識2. API2.1 斷言2.2 setUp() 和 tearDown() 3. Demo 1. 基本知識 unittest 是 Python 標準庫中的一個單元測試框架&#xff0c;用于編寫和執行測試用例以驗證代碼的正確性 提供了一種結構化的方法來編寫測試&#xff0c;使得測試代碼更加模塊化和易于維護 以…

【ACW 服務端】頁面操作Java增刪改查代碼生成

版本: 1.2.2-JDK17-SNAPSHOT 項目地址&#xff1a;wu-smart-acw 演示地址&#xff1a;演示地址 admin/admin Java增刪改查代碼生成 找到對應菜單 選擇你需要的數據實例 選擇數據庫 選擇數據庫表 選擇客戶端&#xff08;如果是本地ACW服務代碼啟動默認注冊上的客戶端ID是…

騰訊云主機Ubuntu22.04安裝Odoo17

一、安裝PostgreSQL16 參見之前的文章 Ubuntu22.04安裝PostgreSQL-CSDN博客 二、安裝Odoo17 本方案使用的nightly版的odoo&#xff0c;安裝的都是最新版odoo wget -O - https://nightly.odoo.com/odoo.key | apt-key add - echo "deb http://nightly.odoo.com/17.0/n…

Maven【1】(命令行操作)

文章目錄 一丶創建maven工程二、理解pom.xml三、maven的構建命令1.編譯操作2.清理操作3.測試操作4.打包操作5.安裝操作 一丶創建maven工程 首先創建這樣一個目錄&#xff0c;然后從命令行里進入這個目錄&#xff1a; 然后接下來就在這個命令行里進行操作了。 這個命令是&…

Python學習筆記——PySide6設計GUI應用之UI與邏輯分離

1、打開PySide6的UI設計工具pyside6-designer&#xff0c;設計一個主窗口&#xff0c;保存文件名為testwindow.ui 2、使用PySide6的RCC工具把testwindow.ui文件轉換為testwindow_rc.py文件&#xff0c;此文件中有一個類Ui_MainWindow&#xff08;包含各種控件對象&#xff09;…

設計模式淺析(八) ·外觀模式

設計模式淺析(八) 外觀模式 日常叨逼叨 java設計模式淺析&#xff0c;如果覺得對你有幫助&#xff0c;記得一鍵三連&#xff0c;謝謝各位觀眾老爺&#x1f601;&#x1f601; 外觀模式 概念 外觀模式&#xff08;Facade Pattern&#xff09;是一種設計模式&#xff0c;它為…

深度學習發展里程碑事件2006-2024

2006-2024年&#xff0c;深度學習發展經歷眾多的里程碑事件&#xff0c;一次次地刺激著人們的神經&#xff0c;帶來巨大的興奮。電影還在繼續&#xff0c;好戲在后面&#xff0c;期待…… 2006年 深度信念網絡&#xff08;DBNs&#xff09;&#xff1a;Geoffrey Hinton與他的學…

備戰藍橋杯 Day10(背包dp)

01背包問題 1267&#xff1a;【例9.11】01背包問題 【題目描述】 一個旅行者有一個最多能裝 M&#xfffd; 公斤的背包&#xff0c;現在有 n&#xfffd; 件物品&#xff0c;它們的重量分別是W1&#xff0c;W2&#xff0c;...,Wn&#xfffd;1&#xff0c;&#xfffd;2&#…

藍橋杯刷題--python-10(2023填空題3)

0工作時長 - 藍橋云課 (lanqiao.cn) import datetime time_str_list=[] while(True):tmp=input()if not tmp: breaktime_str_list.append(tmp)# time_list=[datetime.datetime.strptime(t,"%Y-%m-%d %H:%M:%S")for t in time_str_list] time_list.sort() sum=0 for i…

【代碼隨想錄算法訓練營Day25】● 216.組合總和III ● 17.電話號碼的字母組合

文章目錄 Day 25 第七章 回溯算法part02216.組合總和III自己的思路&#xff08;?通過&#xff09; 17.電話號碼的字母組合思路代碼 Day 25 第七章 回溯算法part02 今日內容&#xff1a; ● 216.組合總和III● 17.電話號碼的字母組合 216.組合總和III 如果把 組合問題理解了…

計算機組成原理(9)----硬布線控制器

控制單元CU若想發出對應的控制信號&#xff0c;則需要以下信息&#xff1a;指令操作碼&#xff0c;目前的機器周期&#xff0c;節拍信號&#xff0c;機器狀態條件&#xff0c;根據這些信息&#xff0c;CU就能確定在這個節拍下應該發出哪些"微命令"&#xff0c;也就是…

SQL注入:使用預編譯防御SQL注入時產生的問題

目錄 前言 模擬預編譯 真正的預編譯 預編譯中存在的SQL注入 寬字節 沒有進行參數綁定 無法預編譯的位置 前言 相信學習過SQL注入的小伙伴都知道防御SQL注入最好的方法&#xff0c;就是使用預編譯也就是PDO是可以非常好的防御SQL注入的&#xff0c;但是如果錯誤的設置了…