Android架構組件:ViewMode概述


作用:

ViewModel 類旨在以注重生命周期的方式存儲和管理界面相關的數據。

問題:

(1) Android 框架可以管理界面控制器(如 Activity, Fragment)的生命周期。由Android 框架響應的某些用戶操作或設備事件,用戶無法控制。    
當系統銷毀或重新創建界面控制器,則存儲在其中的任何臨時性界面相關數據都會丟失。對於簡單的數據,Activity可以使用onSaveInstanceState()存儲數據,組件重建后從onCreate()中的Bundle恢復其數據,但此方法僅適合可以序列化再反序列化的少量數據,如果數據量較大,如用戶列表或位圖,則不適合。

(2)界面控制器經常需要進行異步調用,這些調用可能需要一些時間才能返回結果,有可能會出現UI組件已銷毀,而請求還未返回的情況。在因配置更改而重新創建對象的情況下,對象可能需要重新發送請求,會造成資源的浪費

(3)應該遵循職責分離原則,將視圖數據從界面控制器邏輯中分離出來,這樣不會導致界面控制器類代碼膨脹

ViewModel的用法:

架構組件為界面控制器提供了 ViewModel 輔助程序類,該類負責為界面准備數據。
在配置更改期間會自動保留 ViewModel 對象,以便它們存儲的數據立即可供下一個Activity/Fragment實例使用。如以下示例代碼所示:

public class MyViewModel extends ViewModel {
        private MutableLiveData<List<User>> users;
        public LiveData<List<User>> getUsers() {
            if (users == null) {
                users = new MutableLiveData<List<User>>();
                loadUsers();
            }
            return users;
        }

        private void loadUsers() {
            // Do an asynchronous operation to fetch users.
        }
    }

可以從 Activity 訪問該列表

 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 = ViewModelProviders.of(this).get(MyViewModel.class);
            model.getUsers().observe(this, users -> {
                // update UI
            });
        }
    }

如果Activity被重新創建了,它會收到被之前Activity創建的相同MyViewModel實例。當所屬Activity終止后,框架調用ViewModel的onCleared()方法清除資源。

因為ViewModel在指定的Activity或Fragment實例外存活,它應該永遠不能引用一個View,或持有任何包含Activity context引用的類。如果ViewModel需要Application的context(如獲取系統服務),可以擴展AndroidViewmodel,並擁有一個構造器接收Application。

ViewModel 的生命周期

ViewModel 對象存在的時間范圍是獲取ViewModel時傳遞給ViewModelProvider的Lifecycle。ViewModel將一直留在內存中,直到限定其存在時間范圍的Lifecycle 永久消失:對於 Activity,是在Activity完成時;而對於Fragment,是在Fragment分離時。

上圖左側為Activity的生命周期過程,期間有一個旋轉屏幕的操作;右側則為ViewModel的生命周期過程。
一般通過如下代碼初始化ViewModel:

viewModel = ViewModelProviders.of(this).get(UserProfileViewModel.class);
// this參數一般為Activity或Fragment,因此ViewModelProvider可以獲取組件的生命周期。

Activity在生命周期中可能會觸發多次onCreate(),而ViewModel則只會在第一次onCreate()時創建,然后直到最后Activity銷毀。

在Fragment間共享數據

一個Activity中的多個Fragment相互通訊是很常見的。假設有一個Fragment,在該Fragment 中,用戶從列表中選擇一項,還有另一個Fragment,用於顯示選定項的內容。這種情況不太容易處理,因為這兩個 Fragment都需要定義某種接口描述,並且所有者Activity必須將兩者綁定在一起。此外,這兩個 Fragment 都必須處理另一個Fragment尚未創建或不可見的情況。

可以使用 ViewModel 對象解決這一常見的難點。這兩個Fragment可以使用其 Activity 范圍共享 ViewModel 來處理此類通信,如以下示例代碼所示:

public class SharedViewModel extends ViewModel {
        private final MutableLiveData<Item> selected = new MutableLiveData<Item>();

        public void select(Item item) {
            selected.setValue(item);
        }

        public LiveData<Item> getSelected() {
            return selected;
        }
    }

    public class MasterFragment extends Fragment {
        private SharedViewModel model;
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
            itemSelector.setOnClickListener(item -> {
                model.select(item);
            });
        }
    }

    public class DetailFragment extends Fragment {
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
            model.getSelected().observe(this, { item ->
               // Update the UI.
            });
        }
    }

注意:這兩個Fragment都會檢索包含它們的Activity。這樣,當這兩個Fragment各自獲取ViewModelProvider時,它們會收到相同的SharedViewModel實例(其范圍限定為該Activity)。
此方法具有以下優勢:

* Activity 不需要執行任何操作,也不需要對此通信有任何了解。
* 除了SharedViewModel約定之外,Fragment不需要相互了解。如果其中一個Fragment 消失,另一個Fragment將繼續照常工作。
* 每個Fragment 都有自己的生命周期,而不受另一個Fragment的生命周期的影響。如果一個Fragment替換另一個Fragment,界面將繼續工作而沒有任何問題。

參考:
https://developer.android.google.cn/topic/libraries/architecture/viewmodel.html#java
https://blog.csdn.net/qq_24442769/article/details/79426609
https://blog.csdn.net/zhuzp_blog/article/details/78910535


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM