android.app.activityview,ViewModel 概览
ViewModel 概覽
ViewModel 類旨在以注重生命周期的方式存儲和管理界面相關(guān)的數(shù)據(jù)。ViewModel 類讓數(shù)據(jù)可在發(fā)生屏幕旋轉(zhuǎn)等配置更改后繼續(xù)留存。
注意:如需將 ViewModel導入 Android 項目,請參閱 Lifecycle 版本說明中關(guān)于聲明依賴項的說明。
Android 框架可以管理界面控制器(如 Activity 和 Fragment)的生命周期。Android 框架可能會決定銷毀或重新創(chuàng)建界面控制器,以響應完全不受您控制的某些用戶操作或設(shè)備事件。
如果系統(tǒng)銷毀或重新創(chuàng)建界面控制器,則存儲在其中的任何瞬態(tài)界面相關(guān)數(shù)據(jù)都會丟失。例如,應用可能會在它的某個 Activity 中包含用戶列表。為配置更改重新創(chuàng)建 Activity 后,新 Activity 必須重新提取用戶列表。對于簡單的數(shù)據(jù),Activity 可以使用
另一個問題是,界面控制器經(jīng)常需要進行可能需要一些時間才能返回的異步調(diào)用。界面控制器需要管理這些調(diào)用,并確保系統(tǒng)在其銷毀后清理這些調(diào)用以避免潛在的內(nèi)存泄漏。此項管理需要大量的維護工作,并且在為配置更改重新創(chuàng)建對象的情況下,會造成資源的浪費,因為對象可能需要重新發(fā)出已經(jīng)發(fā)出過的調(diào)用。
諸如 Activity 和 Fragment 之類的界面控制器主要用于顯示界面數(shù)據(jù)、對用戶操作做出響應或處理操作系統(tǒng)通信(如權(quán)限請求)。如果要求界面控制器也負責從數(shù)據(jù)庫或網(wǎng)絡(luò)加載數(shù)據(jù),那么會使類越發(fā)膨脹。為界面控制器分配過多的責任可能會導致單個類嘗試自己處理應用的所有工作,而不是將工作委托給其他類。以這種方式為界面控制器分配過多的責任也會大大增加測試的難度。
從界面控制器邏輯中分離出視圖數(shù)據(jù)所有權(quán)的操作更容易且更高效。
實現(xiàn) ViewModel
架構(gòu)組件為界面控制器提供了 ViewModel 輔助程序類,該類負責為界面準備數(shù)據(jù)。在配置更改期間會自動保留 ViewModel 對象,以便它們存儲的數(shù)據(jù)立即可供下一個 Activity 或 Fragment 實例使用。例如,如果您需要在應用中顯示用戶列表,請確保將獲取和保留該用戶列表的責任分配給 ViewModel,而不是 Activity 或 Fragment,如以下示例代碼所示:
Kotlin
class MyViewModel : ViewModel() {
private val users: MutableLiveData> by lazy {
MutableLiveData>().also {
loadUsers()
}
}
fun getUsers(): LiveData> {
return users
}
private fun loadUsers() {
// Do an asynchronous operation to fetch users.
}
}Java
public class MyViewModel extends ViewModel {
private MutableLiveData> users;
public LiveData> getUsers() {
if (users == null) {
users = new MutableLiveData>();
loadUsers();
}
return users;
}
private void loadUsers() {
// Do an asynchronous operation to fetch users.
}
}
然后,您可以從 Activity 訪問該列表,如下所示:
Kotlin
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Create a ViewModel the first time the system calls an activity's onCreate() method.
// Re-created activities receive the same MyViewModel instance created by the first activity.
// Use the 'by viewModels()' Kotlin property delegate
// from the activity-ktx artifact
val model: MyViewModel by viewModels()
model.getUsers().observe(this, Observer>{ users ->
// update UI
})
}
}Java
public class MyActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
// Create a ViewModel the first time the system calls an activity's onCreate() method.
// Re-created activities receive the same MyViewModel instance created by the first activity.
MyViewModel model = new ViewModelProvider(this).get(MyViewModel.class);
model.getUsers().observe(this, users -> {
// update UI
});
}
}
如果重新創(chuàng)建了該 Activity,它接收的 MyViewModel 實例與第一個 Activity 創(chuàng)建的實例相同。當所有者 Activity 完成時,框架會調(diào)用 ViewModel 對象的 onCleared() 方法,以便它可以清理資源。
注意:ViewModel 絕不能引用視圖、Lifecycle 或可能存儲對 Activity 上下文的引用的任何類。
ViewModel 的生命周期
ViewModel 對象存在的時間范圍是獲取 ViewModel 時傳遞給 ViewModelProvider 的 Lifecycle。ViewModel 將一直留在內(nèi)存中,直到限定其存在時間范圍的 Lifecycle 永久消失:對于 Activity,是在 Activity 完成時;而對于 Fragment,是在 Fragment 分離時。
圖 1 說明了 Activity 經(jīng)歷屏幕旋轉(zhuǎn)而后結(jié)束時所處的各種生命周期狀態(tài)。該圖還在關(guān)聯(lián)的 Activity 生命周期的旁邊顯示了 ViewModel 的生命周期。此圖表說明了 Activity 的各種狀態(tài)。這些基本狀態(tài)同樣適用于 Fragment 的生命周期。
您通常在系統(tǒng)首次調(diào)用 Activity 對象的 ViewModel。系統(tǒng)可能會在 Activity 的整個生命周期內(nèi)多次調(diào)用 ViewModel 存在的時間范圍是從您首次請求 ViewModel 直到 Activity 完成并銷毀。
在 Fragment 之間共享數(shù)據(jù)
Activity 中的兩個或更多 Fragment 需要相互通信是一種很常見的現(xiàn)象。想象一下拆分視圖 (master-detail) Fragment 的常見情況,假設(shè)您有一個 Fragment,在該 Fragment 中,用戶從列表中選擇一項,還有另一個 Fragment,用于顯示選定項的內(nèi)容。這種情況不太容易處理,因為這兩個 Fragment 都需要定義某種接口描述,并且所有者 Activity 必須將兩者綁定在一起。此外,這兩個 Fragment 都必須處理另一個 Fragment 尚未創(chuàng)建或不可見的情況。
可以使用 ViewModel 對象解決這一常見的難點。這兩個 Fragment 可以使用其 Activity 范圍共享 ViewModel 來處理此類通信,如以下示例代碼所示:
Kotlin
class SharedViewModel : ViewModel() {
val selected = MutableLiveData()
fun select(item: Item) {
selected.value = item
}
}
class MasterFragment : Fragment() {
private lateinit var itemSelector: Selector
// Use the 'by activityViewModels()' Kotlin property delegate
// from the fragment-ktx artifact
private val model: SharedViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
itemSelector.setOnClickListener { item ->
// Update the UI
}
}
}
class DetailFragment : Fragment() {
// Use the 'by activityViewModels()' Kotlin property delegate
// from the fragment-ktx artifact
private val model: SharedViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
model.selected.observe(viewLifecycleOwner, Observer { item ->
// Update the UI
})
}
}Java
public class SharedViewModel extends ViewModel {
private final MutableLiveData selected = new MutableLiveData();
public void select(Item item) {
selected.setValue(item);
}
public LiveData getSelected() {
return selected;
}
}
public class MasterFragment extends Fragment {
private SharedViewModel model;
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item);
});
}
}
public class DetailFragment extends Fragment {
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
SharedViewModel model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
model.getSelected().observe(getViewLifecycleOwner(), item -> {
// Update the UI.
});
}
}
請注意,這兩個 Fragment 都會檢索包含它們的 Activity。這樣,當這兩個 Fragment 各自獲取 ViewModelProvider 時,它們會收到相同的 SharedViewModel 實例(其范圍限定為該 Activity)。
此方法具有以下優(yōu)勢:
Activity 不需要執(zhí)行任何操作,也不需要對此通信有任何了解。
除了 SharedViewModel 約定之外,Fragment 不需要相互了解。如果其中一個 Fragment 消失,另一個 Fragment 將繼續(xù)照常工作。
每個 Fragment 都有自己的生命周期,而不受另一個 Fragment 的生命周期的影響。如果一個 Fragment 替換另一個 Fragment,界面將繼續(xù)工作而沒有任何問題。
將加載器替換為 ViewModel
ViewModel 與一些其他類一起使用來替換加載器。使用 ViewModel 可將界面控制器與數(shù)據(jù)加載操作分離,這意味著類之間的強引用更少。
在使用加載器的一種常見方法中,應用可能會使用
圖 2. 使用加載器加載數(shù)據(jù)
ViewModel 與 Room 和 LiveData 一起使用可替換加載器。ViewModel 確保數(shù)據(jù)在設(shè)備配置更改后仍然存在。Room 在數(shù)據(jù)庫發(fā)生更改時通知 LiveData,LiveData 進而使用修訂后的數(shù)據(jù)更新界面。
圖 3. 使用 ViewModel 加載數(shù)據(jù)
將協(xié)程與 ViewModel 一起使用
ViewModel 支持 Kotlin 協(xié)程。如需了解詳情,請參閱將 Kotlin 協(xié)程與 Android 架構(gòu)組件一起使用。
更多信息
隨著數(shù)據(jù)變得越來越復雜,您可能會選擇使用單獨的類加載數(shù)據(jù)。ViewModel 的用途是封裝界面控制器的數(shù)據(jù),以使數(shù)據(jù)在配置更改后仍然存在。如需了解如何在配置更改后加載、保留和管理數(shù)據(jù),請參閱保存界面狀態(tài)。
Android 應用架構(gòu)指南建議構(gòu)建存儲區(qū)類來處理這些功能。
其他資源
如需詳細了解 ViewModel 類,請參閱以下資源。
示例
Sunflower,這是一款園藝應用,展示了使用 Android Jetpack 進行 Android 開發(fā)的最佳做法。
Codelab
博客
視頻
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的android.app.activityview,ViewModel 概览的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python 调用 DLL
- 下一篇: java slot_LocalVaria