MVVMLin
一個基於MVVM用Kotlin+Retrofit+協程+Databinding+LiveData來封裝的快速開發框架:
項目地址:MVVMLin
Github上關於MVVM的框架也不少,之前一直在用RxJava +Retrofit 用MVP模式來做項目,現在AndroidX 是大勢所趨,Kotlin已經成官方語言兩年了,今年GoogleIO大會又出了新東西,哎~~~~學不動了呀。近期項目不太忙,把這幾個新東西結合起來,封裝了一個MVVM的框架,分享出來給大家獻醜了。
拋棄了強大的RxJava,心裏還是有點虛的。
框架簡介
- 使用技術
基於MVVM模式用了 kotlin+協程+retrofit+livedata+DataBinding,默認使用了AndroidX - 基本封裝
封裝了BaseActivity、BaseFragment、BaseViewModel基於協和的網絡請方式更加方便,考慮到有些小夥伴不太喜歡用DataBinding在xml中綁定數據的方式,也提供了相應的適配,兩種方式自行選擇。Retrofit2.6提供了對協程的支持,使用起來更加方便,不用考慮類型的轉換了。 - 特點
使用Rxjava 處理不好的話會有內存泄露的風險,我們會用使用AutoDispose、RxLifecycle等方式來處理,但是使用協程來請求數據,完全不用擔心這個問題,所有請求都是在viewModelScope中啓動,當頁面銷燬的時候,會統一取消,不用關心這個問題了。用Kotlin封裝,大量語法糖可使用。 - 引入第三方庫
AndroidUtilCode:包含了大量的常用工具類,簡直是必備神器啊。
material-dialogs:彈窗
glide:圖片加載
Retrofit:網絡請求
1,如何使用
1.1 啓用databinding
在主工程app的build.gradle的android {}中加入:
dataBinding {
enabled true
}
1.2 依賴
在主項目app的build.gradle中依賴
dependencies {
...
implementation 'me.aleyn:MVVMLin:1.0'
}
或者 下載到本地導入Module
1.3 配置依賴版本文件 config.gradle
如果用本地導入的方式,就要複製Demo的 config,gradle 到根目錄,在項目的build.gradle 中加入:
apply from: "config.gradle"
2,快速開始
2.1Activity
繼承BaseActivity
class DetailActivity : BaseActivity<NoViewModel, ViewDataBinding>() {
override fun layoutId() = R.layout.activity_detail
override fun initView(savedInstanceState: Bundle?) {
....
}
override fun initData() {
....
}
}
第一個泛型是VIewModel,如果頁面很簡單不需要ViewModel,直接傳入NoViewModel即可。
第二個泛型是Databinding,如果頁面使用Databinding的話,就要傳對應生成的Binding類,如果這個頁面不使用DataBinding,傳ViewDataBinding,基類不會初始化mBinding而會使用**setContentView(l)**方式。
layoutId() 方法返回對應佈局
initView() 和 initData() 爲默認實現,做初始化UI等操作
2.2 Fragment
繼承BaseFragment
class HomeFragment : BaseFragment<HomeViewModel, ViewDataBinding>() {
override fun layoutId() = R.layout.home_fragment
override fun initView(savedInstanceState: Bundle?) { }
override fun lazyLoadData() {
....
}
}
實現方法同Activity一樣,Fragment多了懶加載方法lazyLoadData() 可選擇性重寫。
setUserVisibleHint() 方法已經被棄用,懶加載使用新的方式實現。
同樣Fragment中如果想不使用Databinding,泛型傳ViewDataBinding:
2,使用DataBinding,佈局文件:
<layout>
<data>
.....
</data>
.....
</layout>
泛型傳對應生成Binding類:
class ProjectFragment : BaseFragment<ProjectViewModel, ProjectFragmentBinding>() {
.........
}
2.3 ViewModel
繼承BaseViewModel
class HomeViewModel : BaseViewModel() {
.........
}
如果一個頁面內容很少,不需要ViewModel,我們可能不想再建一個ViewModel類,泛型傳NoViewModel即可。
BaseVIewModel 中對協程進行了簡單封裝,BaseViewMode 已經做了對網絡請求異常的統一處理。比如我們的網絡請求可以這樣寫:
class HomeViewModel : BaseViewModel() {
private val homeRepository by lazy { InjectorUtil.getHomeRepository() }
val mBanners = MutableLiveData<List<BannerBean>>()
fun getBanner() {
//只返回結果,其他全拋自定義異常
launchOnlyresult({ homeRepository.getBannerData() }, {
mBanners.value = it
})
}
}
那如果我們想自己處理錯誤怎麼辦?
class HomeViewModel : BaseViewModel() {
private val homeRepository by lazy { InjectorUtil.getHomeRepository() }
val mBanners = MutableLiveData<List<BannerBean>>()
fun getBanner() {
launchOnlyresult({ homeRepository.getBannerData() }, {
mBanners.value = it
},{
// 這裏是Error 返回 ()
})
}
}
只需要加一個方法參數就行了。
另一種不過濾返回結果的方式:
class MeViewModel : BaseViewModel() {
private val homeRepository by lazy { InjectorUtil.getHomeRepository() }
var popularWeb = MutableLiveData<List<UsedWeb>>()
fun getPopularWeb() {
launch({
val result = homeRepository.getPopularWeb() //
if (result.isSuccess()) {
popularWeb.value = result.data
}
})
}
}
要自己處理Error 跟上面一樣,加一個方法參數就行了。
要注意了!!!
Demo中的launchOnlyresult() 方法是用的 BaseResult ,不同項目的 BaseResult肯定是不同的,所以要自己做下擴展,Demo中的 ViewModelExtend 擴展文件中有說明,很詳細的
每個網絡請求都會加等待框,如果我們不想要等待框:
fun getProjectType() {
launchOnlyresult({
homeRepository.getNaviJson()
}, {
navData.addAll(it)
it.forEach { item ->
navTitle.add(item.name)
}
}, isShowDialog = false)
}
isShowDialog 傳false,默認是true
3,例子
Demo中只展示了三種列表使用方式
3.1 不使用Databinging,結合BRVAH
詳見Demo的 HomeFragment
3.2 使用Databinging,結合bindingcollectionadapter
結合bindingcollectionadapter不用寫Adapter適配器了,詳見Demo的 ProjectFragment
3.2 使用Databinging,結合BRVAH
BRVAH 對DataBinding也做了支持,詳見Demo的 MeFragment
4,關於框架
剛剛完成1.0版,也算是我對新東西的一個學習過程,問題應該還是挺多的,後續會進一步完善,下一步會考慮把Eventbus加進去,也歡迎大家多提意見。順手給個Stat。哈哈~~~~