天天看點

MVVM的了解和使用,以及livedata,viewmoel的介紹

因為不太喜歡mvp架構的大量備援代碼,是以呢,很長時間用着被大家诟病的mvc結構。去年呢,kotlin大量的流行了,趁着換kotlin的機會,也換上了mvvm.

一、mvvm的簡單介紹

MVVM是增強關注點分離的體系結構模式之一,它允許将使用者界面邏輯從業務(或者後端)邏輯中分離開來,他的目标(和MVC等其他目标)是為了實作”保持UI代碼簡單化,不涉及更多的業務邏輯,以便于開發者更好的控制和管理”。

MVVM主要有以下幾個層次:

1、Model層

Model層表示使用者程式的資料和業務邏輯,這一層的的推薦的實作政策之一就是觀測資料的變化并傳遞出去(供誰使用),使其從ViewModel或者其他觀察者/消費者中完全解耦

2、ViewModel層

ViewModel是和Model(資料層)進行互動,并且ViewMode可以被View觀察.ViewModel可以選擇性地為視圖提供鈎子以将事件傳遞給模型.該層的一個重要實作政策是将Model與View分離,即ViewModel不應該意識到與誰互動的視圖.

3、View層

此模式中的視圖角色是觀察(或訂閱)ViewMode,觀察資料b變化,以便于擷取資料去更新UI元素.

二、viewmodel

1、LiveData

如上所述,LiveData是新引入的元件架構之一,LiveData是一個可以被觀察的資料持有者.這也就意味着應用中的元件能夠觀察LiveData對象的更改,而無需在它們之間建立明确的和嚴格的依賴關系。這将完全分離LiveData對象使用者和LiveData對象生産者。

除此之外,LiveData還有一個很大的好處,LiveData遵守應用程式元件(活動,片段,服務)的生命周期狀态,并進元件的生命周期管理,確定LiveData對象的記憶體洩漏.

2、ViewModel

ViewModel也是新引入的體系架構元件之一.架構元件提供了一個名為ViewModel的新類,它負責為UI / View準備資料.

ViewModel為您的MVVM模式中的ViewModel提供了一個很好的基類,因為ViewModel(及其子類AndroidViewModel)的擴充類會在配置更改期間自動保留其資料.這意味着,在配

置更改後,此ViewModel所有資料可立即用于下一個活動(activity)或片段(fragment)執行個體.

viewmodel生命周期随view元件的生命周期而銷毀,不會記憶體洩露。ViewModel類是被設計用來以可感覺生命周期的方式存儲和管理 UI 相關資料,ViewModel中資料會一直存活即使 activity configuration發生變化,比如橫豎屏切換的時候。

資料庫結構往往是不能直接跟界面控件一一對應上的,是以,需要再定義一個資料對象專門對應view上的控件。而ViewModel的職責就是把model對象封裝成可以顯示和接受輸入的界面資料對象。

解耦view和model之間,viewmodel作為中間協調,分離出資料操作的職責給 ViewModel,網絡請求和資料庫操作都放到viewmodel進行

簡單的說,ViewModel就是View與Model的連接配接器,View與Model通過ViewModel實作雙向綁定。資料庫結構往往是不能直接跟界面控件一一對應上的,是以,需要再定義一個資料對象專門對應view上的控件。而ViewModel的職責就是把model對象封裝成可以顯示和接受輸入的界面資料對象。

3、viewmodel作用;

1)資料持久化

ViewModel 生命周期是貫穿整個 activity 生命周期,包括 Activity 因旋轉造成的重建立,直到 Activity 真正意義上銷毀後才會結束。既然如此,用來存放資料再好不過了。

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

    private void loadUsers() {
        // do async operation to fetch users
    }
}


public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
        MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
        model.getUsers().observe(this, users -> {
            // update UI
        });
    }
}
           

2)異步回調問題

通常我們 app 需要頻繁異步請求資料,比如調接口請求伺服器資料。當然這些請求的回調都是相當耗時的,之前我們在 Activity 或 fragment裡接收這些回調。是以不得不考慮潛在的記憶體洩漏情況,比如 Activity 被銷毀後接口請求才傳回。處理這些問題,會給我們增添好多複雜的工作。但現在我們利用 ViewModel 處理資料回調,可以完美的解決此痛點。

3、分擔 UI controller負擔

從最早的 MVC 到目前流行的 MVP、MVVM,目的無非是 明确職責,分離 UI controller 負擔。

UI controller 比如 Activity 、Fragment 是設計用來渲染展示資料、響應使用者行為、處理系統的某些互動。如果再要求他去負責加載網絡或資料庫資料,會讓其顯得臃腫和難以管理。是以為了簡潔、清爽、絲滑,我們可以分離出資料操作的職責給 ViewModel。

4、Fragments 間共享資料

比如在一個 Activity 裡有多個fragment,這fragment 之間需要做某些互動。我之前的做法是接口回調,需要統一在 Activity 裡管理,并且不可避免的 fragment 之間還得互相持有對方的引用。仔細想想就知道這是很翔的一件事,耦合度高不說,還需要大量的容錯判斷(比如對方的 fragment 是否還活着)。那麼用 ViewModel 是怎麼樣的呢(官網例子):(activity 與其内部的 fragment 可以共用一個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.
        });
    }
}
           

仔細體會下這樣的好處會發現:

1、Activity 不需要做任何事,甚至不知道這次互動,完美解耦。

2、Fragment 隻需要 與ViewModel互動,不需要知道對方 Fragment 的狀态甚至是否存在,更不需要持有其引用。所有當對方 Fragment 銷毀時,不影響本身任何工作。

3、Fragment 生命周期互不影響,甚至 fragment 替換成其他的 也不影響這個系統的運作。

四、注意

官網用一個大大的紅色感歎号表明:

Caution: A ViewModel must never reference a view, Lifecycle, or any class that may hold a reference to the

activity context.由于 ViewModel 生命周期可能長與 activity 生命周期,是以為了避免記憶體洩漏 Google 禁止在 ViewModel 中持有 Context 或 activity 或 view 的引用。

可以發現 AndroidViewModel 類,内部維護了一個 ApplicationContext ,實在需要可以用這個

public class AndroidViewModel extends ViewModel {
    @SuppressLint("StaticFieldLeak")
    private Application mApplication;

    public AndroidViewModel(@NonNull Application application) {
        mApplication = application;
    }

    /**
     * Return the application.
     */
    @NonNull
    public <T extends Application> T getApplication() {
        //noinspection unchecked
        return (T) mApplication;
    }
}
           

繼續閱讀