前言
使用kotlin协程也有一段时间了,给我最大的感受就是完全可以替代Rxjava了,并且写起来更加的简洁。
6月份Retrofit发布的2.6.0版本内部支持了kotlin协程中的挂起(suspend)修饰符,这就意味着我们可以更加方便的用Retrofit结合kotlin协程来实现网络请求了。
之前我都是使用Rxjava2+Retrofit实现网络请求的功能,然后加入了AutoDispose来实现自动解绑以免发生内存泄漏的问题,感兴趣的可以看看AutoDispose代替RxLifecycle优雅的解决RxJava内存泄漏问题
那协程有没有自动解绑的东西呢。当然有了
目前google官方也给我们提供了androidx.lifecycle:lifecycle-viewmodel-ktx
的依赖包,给ViewModel中扩展了一个作用域叫viewModelScope
viewModelScope是一个绑定到当前viewModel的作用域 当ViewModel被清除时会自动取消该作用域,所以不用担心内存泄漏为问题
那这样一来,我们完全可以使用Retrofit+Coroutines这个方案来代替之前用Retrofit+Rxjava+AutoDispose的方案了。
话不多说,直接上代码
我在网上找了个公开的API接口 https://www.apiopen.top/novelApi
我们就请求这个接口了
添加依赖
首先是添加需要的依赖包,如下
1
2
3
4
5
6
7
8
9
10
11implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.core:core-ktx:1.1.0' implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.1" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.1" implementation "androidx.lifecycle:lifecycle-extensions:2.1.0" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.1.0" implementation "com.squareup.okhttp3:okhttp:4.2.0" implementation "com.squareup.retrofit2:retrofit:2.6.1" implementation "com.squareup.okhttp3:logging-interceptor:4.2.0" implementation "com.squareup.retrofit2:converter-gson:2.6.1"
代码
在看下面的代码之前,你可能需要先看一下下面几篇文章,如果你都知道的话 直接跳过即可
对ViewModel和LiveData 还不是很了解的话先看一下这篇文章
mvp过渡到mvvm(Android 架构组件)
关于一些好用的扩展方法,看一下这个
Kotlin基于RxJava的扩展方法(超级好用)
这里我们主要是看对数据类的扩展,节省一些无用代码
关于Retrofit的工厂类这里我就不放出来了,估计大家的代码都差不多,需要的可以看demo,这里我就不再浪费篇幅,直接用了。
实体类
响应基类
1
2
3
4
5
6data class BaseResp<T>( var code: Int = 0, var msg: String = "", var `data`: T )
小说数据实体类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62package com.yzq.coroutineretofitmvvm.bean import com.google.gson.annotations.SerializedName data class Fiction( var bid: String = "", var bookname: String = "", var introduction: String = "", @SerializedName("book_info") var bookInfo: String = "", var chapterid: String = "", var topic: String = "", @SerializedName("topic_first") var topicFirst: String = "", @SerializedName("date_updated") var dateUpdated: Int = 0, var author: String = "", @SerializedName("author_name") var authorName: String = "", @SerializedName("top_class") var topClass: String = "", var state: String = "", var readCount: String = "", var praiseCount: String = "", @SerializedName("stat_name") var statName: String = "", @SerializedName("class_name") var className: String = "", var size: String = "", @SerializedName("book_cover") var bookCover: String = "", @SerializedName("chapterid_first") var chapteridFirst: String = "", var chargeMode: String = "", var digest: String = "", var price: String = "", var tag: List<String> = listOf(), @SerializedName("is_new") var isNew: Int = 0, var discountNum: Int = 0, @SerializedName("quick_price") var quickPrice: Int = 0, var formats: String = "", @SerializedName("audiobook_playCount") var audiobookPlayCount: String = "", var chapterNum: String = "", var isShortStory: Boolean = false, var userid: String = "", @SerializedName("search_heat") var searchHeat: String = "", @SerializedName("num_click") var numClick: String = "", @SerializedName("recommend_num") var recommendNum: String = "", @SerializedName("first_cate_id") var firstCateId: String = "", @SerializedName("first_cate_name") var firstCateName: String = "", var reason: String = "" )
定义请求接口
这个没什么好说的,需要注意的就是我们的方法前面用 suspend 修饰
1
2
3
4
5interface ApiService { @GET("https://www.apiopen.top/novelApi") suspend fun getFictions(): BaseResp<List<Fiction>> }
用于解析响应数据的扩展方法
1
2
3
4
5
6
7
8
9/*数据解析扩展函数*/ fun <T> BaseResp<T>.dataConvert(): T { if (code == 200) { return data } else { throw Exception(msg) } }
ViewModel
注释也很详细了,这里就不多说了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30class NetViewModel : ViewModel() { var fictions = MutableLiveData<List<Fiction>>() fun getFictions() { /*viewModelScope是一个绑定到当前viewModel的作用域 当ViewModel被清除时会自动取消该作用域,所以不用担心内存泄漏为问题*/ viewModelScope.launch { try { /*dataConvert扩展函数可以很方便的解析出我们想要的数据 接口很多的情况下下可以节省不少无用代码*/ val data =RetrofitFactory.instance.getService(ApiService::class.java) .getFictions().dataConvert() /*给LiveData赋值 ui会自动更新*/ fictions.value = data } catch (e: Exception) { /*请求异常的话在这里处理*/ e.printStackTrace() Log.i("请求失败", "${e.message}") } } } }
Activity
Activity中代码就很简单了,主要就是创建ViewModel示例,更新ui
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22class MainActivity : AppCompatActivity() { private lateinit var netViewModel: NetViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) /*创建viewmodel*/ netViewModel = ViewModelProviders.of(this).get(NetViewModel::class.java) btn.setOnClickListener { /*请求数据*/ netViewModel.getFictions() } /*数据发生变化时更新ui*/ netViewModel.fictions.observe(this, Observer { tv.text = Gson().toJson(it) }) } }
下面我们来看看运行结果:
可以看到,网络请求的功能已经实现了。
那对比RxJava的实现方式,你觉得哪种方式更好呢?
好了,本篇文章到此结束。
demo
如果你觉得本文对你有帮助,麻烦动动手指顶一下,算是对本文的一个认可,如果文中有什么错误的地方,还望指正,转载请注明转自喻志强的博客 ,谢谢!
最后
以上就是鲤鱼八宝粥最近收集整理的关于Retrofit+kotlin Coroutines(协程)+mvvm(Jetpack架构组件)实现更简洁的网络请求的全部内容,更多相关Retrofit+kotlin内容请搜索靠谱客的其他文章。
发表评论 取消回复