Kotlin + MVVM 简单搭建示例

Kotlin + MVVM + Jetpack 学习系列

一、本文主要内容

Kotlin + MVVM 简单搭建示例

二、MVVM结构

首先介绍下什么是MVVM,相信做Android开发的对MVC/MVP都不陌生,MVVM也一样,也是一种设计架构。
在这里插入图片描述
在这里插入图片描述

层级描述
View对应Activity/Fragment以及XML,负责View的绘制、用户交互
ViewModel业务逻辑,作为桥梁处理View和Model直接的交互
Model数据的处理,如网络请求、查询SQLite等

这么一看,是不是感觉ViewModel和Presenter蛮像的,但是他们的实现方式是不一样的,在MVVM中,这些是通过数据驱动来自动完成的,数据变化后会自动更新UI,UI的改变(用户输入内容等)也能更新到数据层。

三、简单Demo示例

以帐号登录为例,下面介绍下如何快速搭建各层代码。

3.1 Model层

这里省略了具体的网络请求类,只定义了一个LoginInfo的Bean类。
很简单,三个属性,继承BaseObservable,并在数据被修改后进行notifyChange()。

class LoginInfo: BaseObservable() {
    var name: String = ""
        set(value) {
            if (name != value) {
                field = value
                notifyChange()
            }
        }
    var pwd: String = ""
        set(value) {
            if (pwd != value) {
                field = value
                notifyChange()
            }
        }
    var state: String = ""
        set(value) {
            field = value
            notifyChange()
        }
}

3.2 ViewModel层

创建MutableLiveData对象,这里泛型<>就是我们的LoginInfo,还有就是对LoginInfo做一个对象初始化,以及定义了一个login()的方法(下面讲到View层的时候会用到)。

class CusViewModel : ViewModel() {
    /**
     * 一个可被观察的数据类,并且能感知View(Activity等)生命周期
     * databinding后view的输入,或者数据的改变均会通知到双方
     */
    val loginInfoData = MutableLiveData<LoginInfo>()

    init {
        // 初始化loginInfo对象
        loginInfoData.value = LoginInfo()
    }

    fun login() {
        // 模拟登录,正常场景应通过model层进行网络请求等
        val loginInfo = loginInfoData.value
        if (loginInfo != null) {
            if ("123" == loginInfo.name && "123" == loginInfo.pwd) {
                loginInfo.state = "成功"
            } else {
                loginInfo.state = "失败"
            }
        }
    }
}

3.3 View层

包含Acitivity和XML布局文件的编写,主要实现View与ViewModel形成绑定关系。

3.3.1 XML

先对XML布局进行转换,通过Alt+Enter会有提示“Convert to data bindling layout”,转换后会多出一组data标签,其中声明我们的ViewModel对象
在这里插入图片描述

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <variable
            name="cusViewModel"
            type="com.ycl.kotlinapplication.mvvm.viewmodel.CusViewModel" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <EditText
            android:id="@+id/ed_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="姓名"
            android:text="@={cusViewModel.loginInfoData.name}" />

        <EditText
            android:id="@+id/ed_age"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="密码"
            android:text="@={cusViewModel.loginInfoData.pwd}" />

        <TextView
            android:id="@+id/tv_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{cusViewModel.loginInfoData.name}" />

        <TextView
            android:id="@+id/tv_age"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{cusViewModel.loginInfoData.pwd}" />

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="@{()->cusViewModel.login()}"
            android:text="登录" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{cusViewModel.loginInfoData.state}" />

    </LinearLayout>
</layout>

可以看见在Edittext/TextView中直接使用了cusViewModel.loginInfoData.xxx的属性值对view的text属性赋值,同时Button的点击事件调用到cusViewModel.login()方法。

补充:
@={} 代表双向绑定(view的输入影响数据本身,数据本身变化影响view的展示)
假设上诉Edittext这里改成单向绑定,你觉得体验是什么样?
@{} 代表单向绑定

3.3.2 Activity

1.创建ViewModel
2.DataBinding绑定布局
3.DataBinding与ViewModel关联
这样就可以把View与ViewModel关联起来了

class CusViewActivity : AppCompatActivity() {

    private lateinit var mBinding: ActivityCusviewBinding
    private lateinit var mCusViewModel: CusViewModel
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 创建ViewModel
        mCusViewModel = ViewModelProvider(this).get(CusViewModel::class.java);
        // DataBinding绑定布局
        mBinding =
            DataBindingUtil.setContentView<ActivityCusviewBinding>(this, R.layout.activity_cusview)
        // 代码初始化LoginInfo信息(会直接刷新到View中)
        /*val loginInfo = mCusViewModel.loginInfoData.value
        if (loginInfo != null) {
            loginInfo.name = "123"
            loginInfo.pwd = "345"
        }*/
        // DataBinding与ViewModel关联
        mBinding.cusViewModel = mCusViewModel
    }
}

3.4 预览

在这里插入图片描述

五、总结

MVVM简化了对view的繁琐操作,可以看到上诉代码不需要再对view设置监听来获取输入内容等。通过数据绑定机制,实现了Model和View的自动更新,降低了代码的复杂度。同时减少手动对生命周期的管理,降低内存泄漏风险。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
当然,我很愿意回答您的问题。下面是一个 Kotlin + 协程 + Retrofit + MVVM 实现网络请求的示例: 1. 在 build.gradle 中添加以下依赖: ``` implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0' implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0' implementation 'com.squareup.retrofit2:retrofit:2.8.1' implementation 'com.squareup.retrofit2:converter-gson:2.8.1' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9' ``` 2. 创建 Retrofit 接口: ```kotlin interface ApiService { @GET("users/{user}/repos") suspend fun getRepos(@Path("user") user: String): List<Repo> } ``` 3. 创建数据模型: ```kotlin data class Repo(val name: String) ``` 4. 创建 Repository: ```kotlin class MainRepository(private val apiService: ApiService) { suspend fun getRepos(user: String): List<Repo> { return apiService.getRepos(user) } } ``` 5. 创建 ViewModel: ```kotlin class MainViewModel(private val repository: MainRepository) : ViewModel() { private val _repos = MutableLiveData<List<Repo>>() val repos: LiveData<List<Repo>> = _repos fun getRepos(user: String) { viewModelScope.launch { _repos.value = repository.getRepos(user) } } } ``` 6. 创建 Activity/Fragment: ```kotlin class MainActivity : AppCompatActivity() { private lateinit var viewModel: MainViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val apiService = Retrofit.Builder() .baseUrl("https://api.github.com/") .addConverterFactory(GsonConverterFactory.create()) .build() .create(ApiService::class.java) val repository = MainRepository(apiService) viewModel = ViewModelProvider(this, MainViewModelFactory(repository))[MainViewModel::class.java] viewModel.repos.observe(this, Observer { repos -> // do something with repos }) viewModel.getRepos("octocat") } } ``` 以上就是一个使用 Kotlin + 协程 + Retrofit + MVVM 实现网络请求的示例。希望对您有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值