天天看點

安卓基于Mvvm架構模式重構實戰

在經曆了把項目的5個modules合并成一個Module為app-framwork Moudle外,項目目前的app module有非常多的和業務無關的代碼。是以目前必須需要采用一種架構模式來對項目進行重構,來達到簡化項目邏輯,實作代碼之間的高内聚、低耦合,降低今後的代碼維護成本。

下面我們來一起學習一下這個架構模式吧。從github下載下傳了目前最火的Mvvm架構MvvmHabit。

之前的項目架構分了很多的module,但是業務實作上卻沒有使用mvc、mvp、mvvm的架構模式進行分包,是以現在就需要對架構重新設計。

第一版設計架構模式如下:

安卓基于Mvvm架構模式重構實戰

這裡我是根據項目的業務需求來劃分的架構,首先項目有三個主要子產品,點選app圖示之後跳轉到首頁、任務頁面、我的頁面。一共是三個子產品,是以我當時的第一想法就是按子產品來劃分業務代碼,然後子產品裡面按類的職能劃分,如activity、fragment、adapter、還有就是資料實體類model.然後跟項目總監讨論之後,項目這個架構不适合代購變動,就是說任何一個module發生變化都會讓項目的架構重新設計,改動太大。讨論解決使用下面這種架構模式:

安卓基于Mvvm架構模式重構實戰

這種模式符合目前項目的架構模型,代碼改動也比較小。最後總監的一個建議是:”最好使用開源架構MvvmHabit的架構包,直接引入這個架構包來實作項目的開發。這樣就可以參與開源,發現問題也可以送出代碼到開源架構,成功開源項目的貢獻者。這個目前還在考慮,因為項目目前代碼比較龐大,如果從整個架構上重構成開源架構的模型,需要比較長的開發時間和代碼改動太大,測試時間也比較大。

目前就是對Mvvm架構模式了解不是很深,雖然知道它主要就是基于安卓提供data binding架構來使布局界面和資料進行綁定,但是網絡請求該在哪裡請求?如何更新資料實體類來重新整理界面顯示?最主要的核心是什麼?應該注意什麼?如何回收記憶體等等問題,都是需要考慮到的。

現在就是需要找到一個有實戰經驗的app來了解整個Mvvm架構模型。

首先這裡說到的Mvvm其實可以直接了解成一種程式設計思想,它是基于mvp架構模式把p層使用ViewModel來替代,這裡的ViewModel實作了和View層和Model層的雙向綁定,簡化了我們之前通過findViewById去查找到一個控件,再給控件指派的過程。

這裡我們還需要了解兩個Google提供的架構支援包,分别是2015推出的Data Banding還有就是2017年推出的ACC(Attributes Components Compatibilities)是Google測試團隊使用的一種模組化方法,用來快速地建立産品的模型,以指導下一步的測試計劃和設計。這裡我們可以了解Acc為是一種架構思想。

于是我就在Google官網上查找優化Data Banding和Acc的資料,但是并沒有收獲。

安卓項目使用Data Banding需要在項目的build.gradle檔案下新增如下代碼,如果項目有多個Module,需要在每一個Module的android目錄下添加:

dataBinding {
        enabled true
    }
           

在需要使用DataBanding的build.gradle檔案下面加入:

classpath "com.android.databinding:dataBinder:1.0-rc0"
           

在每一個你想要使用Data Binding的module,添加如下的插件:

apply plugin: ‘com.android.application'
apply plugin: 'com.android.databinding'   
           

Data Binding表達式

Data Binding layout檔案有點不同的是:起始根标簽是 layout,接下來一個 data 元素以及一個 view 的根元素。這個 view 元素就是你沒有使用Data Binding的layout檔案的根元素。舉例說明如下:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.firstName}"/>
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.lastName}"/>
   </LinearLayout>
</layout>
           

在 data 内描述了一個名為user的變量屬性,使其可以在這個layout中使用:

<variable name="user" type="com.example.User"/>
           

在layout的屬性表達式寫作@{},下面是一個TextView的text設定為user的firstName屬性:

<TextView android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@{user.firstName}"/>
           

Binding資料

預設情況下,一個Binding類會基于layout檔案的名稱而産生,将其轉換為Pascal case(譯注:首字母大寫的命名規範)并且添加“Binding”字尾。上述的layout檔案是activity_main.xml,是以生成的類名是ActivityMainBinding。此類包含從layout屬性到layout的Views中所有的bindings(例如user變量),并且它還知道如何給Binding表達式配置設定數值。建立bindings的最簡單的方式是在inflating(譯注:layout檔案與Activity/Fragment的“連結”)期間如下:

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity);
   User user = new User("Test", "User");
   binding.setUser(user);
}
           

就是這樣,運作app後,你将會看到Test User。或者你可以通過如下擷取View:

MainActivityBinding binding = MainActivityBinding.inflate(getLayoutInflater());
           

如果你在ListView或者RecyclerView adapter使用Data Binding時,你可能會使用:

ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup,
false);
//or
ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);
           

這裡就先簡單的介紹Android data banding就先簡單介紹到這裡了,如果大家想更進一步了解Data Banding這種插件的源碼實作,可以移步到“深入解析Android Data Banding架構源碼”。

還有就是這裡我們需要了解Acc是什麼?

下面我就直接引入一篇架構嘗試的部落格文章了-----”Android之Acc架構嘗試“。

最後我們再來分析一下MVVMHabit-master這個開源架構的結構組成和源碼分析。

這個架構最主要的功能就是提供了一個mvvmhabit元件包,這個元件包可以直接導入源碼,也可以通過在build.gradle裡面關聯倉庫位址來引入這個包。如何使用我們還是移步到MVVMHabit-master開源架構吧。