以前項目中雖然也使用MVVM架構,但由于整體框架不是我自己搭建的,導致我對于MVVM架構的整體還是很不熟悉,所以這次就自己搭建并實現一次MVVM架構。
MVVM架構使用的組件有ViewModel、LiveData、ViewBinding/DataBinding等,這些組件都是Jetpack庫中的組件。在使用ViewModel之前要先建立四個類別的概念:
- ViewModelProcider.Factory:Factory用來生成ViewModel
- ViewModel:持有LiveData,從Repository獲取數據,并向View提供數據
- Repository:獲取和處理數據,可以從網絡、數據庫或其他API獲取并處理數據
- LiveData:具有生命周期感知能力的可觀察的數據存儲器,通知View展示數據
下圖展示了MVVM架構示意圖,以及相關組件在其中的作用。

了解了MVVM的基本架構和其中各個組件的作用,可以開始代碼實現了。我做這個項目的初衷是因為最近在整理收集Android常用的開源庫,為了更方便的展示所實現的一個應用。本項目使用Bmob直接作為后臺數據庫,接入Bmob SDK后調用API可以直接獲取數據,以此來模擬后臺接口。同時本項目使用Koin作為依賴注入的框架,省去初始化ViewModel、Repository、ViewModelProcider.Factory的過程。
先貼上項目目錄,需要關注的是高亮顯示的文件(使用Koin省去了Factory類的實現):

-
ViewModel類:
實現HomeViewModel類,需要繼承繼承自ViewModel(),作為HomeFragment的ViewModel。HomeViewModel類的構造參數是BmobRepository,類中有一個LiveData變量用來承載數據,一個函數getAllRecommendLibrary()獲取開源庫數據,函數實現是repository在協程中獲取云數據庫中的數據:
class HomeViewModel(private val repository: BmobRepository) : ViewModel() {
var libraryRecommendData = MutableLiveData<MutableList<AndroidLibrary>>()
fun getAllRecommendLibrary() {
viewModelScope.launch {
repository.getAllRecommendLibrary(libraryRecommendData)
}
}
}
-
Repository類:
實現BmobRepository類,作為HomeViewModel的數據提供方。BmobRepository類中有一個掛起函數getAllRecommendLibrary(libraryRecommendData: MutableLiveData<MutableList<AndroidLibrary>>)用來獲取云數據庫中的數據,函數的參數是LiveData,在獲取數據后,利用setValue通知View展示數據。
class BmobRepository {
/**
* 獲取Bmob中所有推薦開源項目
*/
suspend fun getAllRecommendLibrary(libraryRecommendData: MutableLiveData<MutableList<AndroidLibrary>>) {
return withContext(Dispatchers.IO) {
val bombQuery: BmobQuery<AndroidLibrary> = BmobQuery()
bombQuery.findObjects(object : FindListener<AndroidLibrary>() {
override fun done(data: MutableList<AndroidLibrary>?, ex: BmobException?) {
if (ex == null) {
Timber.d("Bmob find success")
libraryRecommendData.value = data!!
} else {
Timber.d("Bmob exception $ex")
}
}
})
}
}
}
-
Koin初始化:
Koin的初始化分為兩步:
定義ViewModel,告訴Kioin從哪里找到ViewModel和Repository并自動生成,這里我選擇直接寫在BaseApplication中,需要注意的是需要定義在最外層,即和Classt同級:
在Application的onCreate()函數中初始化Koin:
class BaseApplication : Application() {
override fun onCreate() {
super.onCreate()
//初始化Bmob
Bmob.initialize(this, Constant.BMOB_APP_ID)
//初始化Timber
if (BuildConfig.DEBUG) {
Timber.plant(Timber.DebugTree())
}
//第二步:
startKoin {
//Android context
androidContext(this@BaseApplication)
//modules
val list = listOf(myModule, repoModel)
modules(list)
}
}
}
//第一步:
//定義一個myModule作為Viewmodel
val myModule = module {
viewModel { HomeViewModel(get()) }
}
//定義一個repoModule
val repoModel = module {
single { BmobRepository() }
}
- Fragment類實現:
實現HomeFragment類作為視圖層,其中分為兩步:-
變量homeViewModel作為ViewModel獲取數據,使用Koin后的初始化方式十分簡單
private val homeViewModel: HomeViewModel by viewModel()//懶加載初始化 -
LiveData注冊監(jiān)聽ViewModel中的數據改變,并實現獲取數據后的操作
private fun initRegister() { //LiveData在視圖層中注冊監(jiān)聽后,在ViewModel中的數據改變時可以持續(xù)收到數據 homeViewModel.libraryRecommendData.observe(viewLifecycleOwner, { Timber.d("t $it") (binding.rvAndroidLibrary.adapter as AndroidLibraryAdapter).apply { data = it notifyDataSetChanged() } }) }- ViewModel調用函數通知Repository去查詢數據:
override fun onResume() { super.onResume() homeViewModel.getAllRecommendLibrary() }
-
自此,一個MVVM架構的應用搭建完成,第一次獨立的搭建MVVM架構之后,對于MVVM架構的理解加深了不少,對于JetPack庫中的組件和其它開源庫也有了新的認識,此外MVVM架構還經常和Retrofit、RxJava等開源庫配合使用,希望以后有機會可以再進行實踐操作?。?/p>
參考文章:Android MVVM 架構-使用 ViewModel、LiveData、Factory 以及 Repository
本項目源代碼android_all_star_app
本項目使用開源組件庫:koin、timber、permissionx、BaseRecyclerViewAdapterHelper