一、 Android MVVM 概念讲解:
转载:https://blog.csdn.net/weixin_44715733/article/details/130772996
没有相关概念的,一定要先观看上面链接内容。
转载协程:Android协程_android 协程-CSDN博客
协程介绍请观看上面链接内容。
二、MVVM使用的前期准备工作:
先看看运行效果图:
1.引入相关依赖:
在项目级别build.gradle,引入dataBinding.
2.由于dataBinding继承于viewbinding,所以以前我们写的BaseActivity,BaseFragment依然可以使用。
3.BaseActivity中需要添加的点:
需要再onCreate中添加如下代码
if (binding is ViewDataBinding){
(binding as ViewDataBinding).lifecycleOwner=this
}
在onDestroy()中移除
if (binding is ViewDataBinding) {
(binding as ViewDataBinding).lifecycleOwner = null
}
在BaseFragment,也是在生命周期的开始添加和结束的时候移除,原理同上。
三、MVVM的简单使用:
我们就接着在上一章的MVP应用上接着使用,新增天气模块,这个模块就使用MVVM模式。
我们看看MainActivity内容
我们在看看TabMainBinding布局:
这里我们优先看看TabNewsFragment,只有一点点变动,其他与上一章节的MainActivity一模一样。
//新闻模块
class TabNewsFragment :
BaseMVPFragment<FragmentTabnewsBinding, List<TabNewsData>, TabNewsPresenter>() {
//之所以需要再可见的时候去获取Tab数据。是因为是短时间类,接口调用多次,会被拦截
private var isSetTab = false
override fun initData(savedInstanceState: Bundle?) {}
//界面可见
override fun onResume() {
super.onResume()
if (!isSetTab) {
LoadingDialogManager.loadingDialog(requireActivity(), "加载数据中") //启动一个弹出提示用户正在获取数据
presenter.startGetData() //通过P层,获取数据
}
}
override fun dataCall(state: Int, message: String, dataList: List<TabNewsData>?) {
LoadingDialogManager.loadOff() // 这是获取到数据。第一件事是关闭弹窗
if (state == 200 && !dataList.isNullOrEmpty()) {
isSetTab = true
setNewsTab(dataList) //200即返回的List不为null 直接下一步操作
} else {
message.showToast() //否则看看返回的信息消息是什么。
}
}
//这里是实现导航栏效果
private fun setNewsTab(dataList: List<TabNewsData>) {
val fragments = mutableListOf<Fragment>() //准备与之对应的Fragment
dataList.forEach { //循环List,把每一Item放在对应的NewsFragment中
fragments.add(NewsFragment().apply {
// 这里 初始化数据传递给Fragment使用setArguments(Bundle args)方法
// 不可以使用构造方法传递参数,使用构造方法传递参数,数据会丢失
// MyBundleUtils,一个封装类,Bundle 数据的封装
arguments = MyBundleUtils.setKeyData(it)
})
}
//这里是我封装的 tabLayout 和ViewPage2的一个封装类,
NavigationBarHManager<ItemTabBinding, TabNewsData>(binding.tabLayout, binding.viewPager2)
.setDataSources(fragments, dataList)
.setOffscreenPageLimit(-1)
.setTabMode(TabLayout.MODE_SCROLLABLE)
.tabViewBinding { ItemTabBinding.inflate(layoutInflater) }
.tabLinkage { binding, isChoose, data, _ ->
binding.tvTabName.text = data.typeName
binding.viewBg.visibility = if (isChoose) View.VISIBLE else View.INVISIBLE
}
.build(this)
}
}
接下来我们正式进入天气模块(WeatherFragment)的MVVM的使用。
1.先看看WeatherFragment
接下来,我们看看FragmentWeatherBinding布局:
<?xml version="1.0" encoding="utf-8"?>
<layout>
<!--dataBinding 必须使用layout 包含你的布局-->
<!-- 这里data 可以是ViewModel,也可以是数据实体类,当然还有其他-->
<!-- variable 可以设置多个,使用的时候,设置相关值即可-->
<!-- viewModel-->
<data>
<variable
name="viewModel"
type="com.tmg.project.model.WeatherModel" />
<!-- <variable-->
<!-- name=""-->
<!-- type="" />-->
</data>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- 这里的内容text使用viewModel中的address-->
<!--当其变化的时候,TextView的内容也会变化-->
<!--这里dataBinding,会自动切换到主线程更新ui,不用担心子线程变更数据,出现异常-->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:text="@{viewModel.address}"
android:textSize="20sp"
android:textStyle="bold" />
<!--这里自定义了一个BindingAdapter方法,使用的viewModel.weatherListData-->
<!--weatherListData数据变更,便会触发 setRecyclerViewAdapter方法-->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvWeatherList"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="10dp"
android:layout_weight="1"
android:overScrollMode="never"
app:setRecyclerViewAdapter="@{viewModel.weatherListData}" />
</LinearLayout>
</layout>
我们看看setRecyclerViewAdapter自定义的方法:
我看看WeatherAdapter:
ItemWeatherBinding代码如下:
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="data"
type="com.tmg.project.data.ForecastsData" />
</data>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:paddingTop="10dp"
android:paddingBottom="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:text="@{data.date}"
android:textColor="@color/black"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:text="@{data.week}"
android:textColor="@color/black"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_weight="1"
android:gravity="center"
android:text="@{data.dayWeather}"
android:textColor="@color/black"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:gravity="center"
android:text="@{data.nightTemp}"
android:textColor="@color/black"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="/"
android:textColor="@color/black"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:gravity="center"
android:text="@{data.dayTemp}"
android:textColor="@color/black"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
</layout>
在接下来,我们看看WeatherModel内容:ViewModel是databinding自带的,所有MVVM的Model层都是继承于ViewModel。ViewModl,可以在设备切换的时候,保证数据不遗失。
接下来我们看看RetrofitManager调用的方法和返回数据内容(这里和上一章的RetrofitManager使用是一样的,使用公共的接口,不过在方法上有点变动)
接下来,我们看看WeatherData、ForecastsData
data class WeatherData(
val address: String,
val cityCode: String,
val reportTime: String,
val forecasts: List<ForecastsData>,
)
代码部分就差不多,只是简单的一个使用;后续使用肯定会更多。一起学习进步!