协程+Retrofit+ViewModel+LiveData+DataBinding

介绍协程+Retrofit+ViewModel+LiveData+DataBinding的框架搭建,实现从网络请求api接口功能,相关demo

一、框架搭建

整体项目结构如下

image-20220127202810611

1.1、环境、依赖库配置

新建项目,在app的build.gradle中添加依赖

    //retrofit
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-moshi:2.9.0'

    //coroutines
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0-RC-native-mt'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0-RC-native-mt'

    //viewModels
    implementation "androidx.activity:activity-ktx:1.1.0"

因为涉及到http网络请求,配置manifest权限

<uses-permission android:name="android.permission.INTERNET" />

application节点下的http权限

android:networkSecurityConfig="@xml/network_security_config"

xml -> network_security_config.xml

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

app的build.gradle中配置databinding

android {
    ...
    dataBinding {
        enabled = true
    }
}

gradle.properties中配置debug包运行

android.injected.testOnly=false

1.2、创建api网络请求

新建UserApi.kt,这里简单实现数据解析的User实体类,服务器返回json

{
    "name": "jason",
    "address": "California"
}
// 定义User数据实体类
data class User(val name: String, val address: String)

// retrofit网络请求
val userServiceApi: UserServiceApi by lazy {
    val retrofit = retrofit2.Retrofit.Builder()
        .client(OkHttpClient.Builder().addInterceptor {
            it.proceed(it.request()).apply {
                Log.d("jason", "request:${code()}")
                //Log.d("jason", "boy:${body()?.string()}")
            }
        }.build())
        .baseUrl("http://81.68.175.49:8080/kotlinstudyserver/")
        .addConverterFactory(MoshiConverterFactory.create())
        .build()
    retrofit.create(UserServiceApi::class.java)
}

// 请求接口
interface UserServiceApi {

    @GET("user")
    fun loadUser(@Query("name") name: String) : Call<User>

    @GET("user")
    suspend fun getUser(@Query("name") name: String) : User
}

1.3、创建viewmodel

创建MainViewModel继承自ViewModel()

class MainViewModel: ViewModel() {
}

根据google官方指南,我们是在ViewModel中通过repository去请求网络、数据库的数据

因此这里还需要新建UserRepository

class UserRepository {
    suspend fun getUser(name: String): User {
        return userServiceApi.getUser(name)
    }
}

因为这里继承自ViewModel,所以这里带了viewModelScope

MainViewModel部分代码:

class MainViewModel: ViewModel() {
    //liveData
    val userLiveData = MutableLiveData<User>()

    private val userRepository = UserRepository()

    fun getUser(name: String) {
        viewModelScope.launch {
            userLiveData.value = userRepository.getUser(name)
        }
    }
}

1.4、加载数据

activity_main.xml中绘制mvvm绑定视图

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

    <data>

        <variable
            name="viewModel"
            type="com.example.retrofitviewmodellivedatadatabinding.viewmodel.MainViewModel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">


        <Button
            android:id="@+id/submitButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="104dp"
            android:text="提交"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@+id/guideline" />

        <TextView
            android:id="@+id/nameTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{viewModel.userLiveData.name}"
            android:textSize="18sp"
            app:layout_constraintBottom_toTopOf="@+id/guideline"
            app:layout_constraintHorizontal_bias="0.484"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.681" />

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/guideline"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            app:layout_constraintGuide_percent="0.5" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

activity中加载数据set到布局上

class MainActivity : AppCompatActivity() {
    private val mainViewModel: MainViewModel by viewModels()

    @SuppressLint("StaticFieldLeak")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 设置布局
        val binding =
            DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
        // 指定viewModel
        binding.viewModel = mainViewModel
        // 在 xml 中使用 LiveData
        binding.lifecycleOwner = this
        binding.submitButton.setOnClickListener {
            mainViewModel.getUser("xxx")
        }
    }
}

二、设计好在哪里

2.1、viewModel解决Activity很可能会被销毁重建,页面的状态将会丢失

如下图所示页面旋转时,CoroutineDemo数据销毁了,而使用了ViewModel的数据仍然存在

image-20220127202810611

2.2、协程解决了回调地狱的问题

在网络请求中,协程将异步任务同步化,优化了代码可读性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流星雨在线

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值