Android开发笔记:Retrofit + OkHttp3 + coroutines + LiveData打造一款网络请求框架

tech2023-07-16  121

一个好的网络框架需要有那些特点呢?

请求 当然这个请求不单单是发送请求这么简单,它包括请求相关的一系列配置是否简易、发送模式是否灵活切换、请求头信息是否易处理、请求参数是否易操作等等响应 一个好的网络请求框架肯定需要提高我们的生产力,保证我们程序的健壮性,那么响应体和这些又有什么关系呢? 容易转换成不同需求的实体 是否能返回不同类型的结构。xml、json、text等等

总的来说就是易使用、易扩展、可读性高

一、目的

背景

市场上现在存在的网络请求不在少数,从原生的HttpClient 到 OkHttp、Volley、xUtils 无疑都是将网络请求简单化、方便、安全等用以提升开发的效率以及程序的质量。后面出现Retrofit ,将OkHttp3 进行了封装,将请求API 接口化,将返回的数据结合GSON等各种转换器转换为直接面向开发的对象,大大的提升了我们的开发效率,为了解决Android UI/子线程 负责的功能场景方便切换,大家开始结合了RxJava, 这一操作直接将Retrofit + OkHttp3 + RxJava 组合的网络框架推上了热门写法,

现状

kotlin 的出现是Google 对于Android开发的重新定义,含糊不清的态度,既不丢弃Java又宣布kotlin 是首选语言。在次基础上结合jetpack框架,成了新时代开发的另一条选择路径,从始至终Google 没有对Android推出过官方的设计模式,大家都是从高内聚、低耦合等方面推行着自己的设计模式,让开发简单、维护简单、程序健壮。jetpack是Google 对设计模式的首次官方制造,重点可想而知,那在这个基础上我们还需要使用之前的网络框架吗?有没有更加优秀的框架以及框架的组合使得我们的程序健壮、开发简易呢?

jetpack

具体的jetpack不是这里解释的。其中ViewModel - LiveData 已经得到了广大开发者的认可,ViewModel 和LiveData 的结合,使得Android中数据可控性变得更好,耦合度更低,简单来说是官方将观察者模式用于到了真个数据结构中,在这里也是将要结合其他框架来完成网络框架的设计

coroutines

kotlin较Java的最大变化就是kotlin推出的coroutines (协程),协程完全可以替代RxJava, Thread、多级接口回调等,并且有上下文及各种模式来迎合各种场景,具体不再这里解释,

使用上述出现的几个框架完成新的网络请求框架的封装

二、组合框架

2.1 添加依赖

//LifeCycle implementation 'androidx.lifecycle:lifecycle-common:2.2.0' implementation 'androidx.lifecycle:lifecycle-runtime:2.2.0' implementation 'android.arch.lifecycle:extensions:2.2.0' implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0' //Retrofit implementation "com.squareup.retrofit2:retrofit:2.9.0" implementation "com.squareup.okhttp3:logging-interceptor:4.2.0" implementation "com.squareup.retrofit2:converter-gson:2.9.0" implementation 'com.squareup.retrofit2:converter-scalars:2.6.2' //Coroutines implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7' //Kotlin extensions for activity and fragments implementation 'androidx.fragment:fragment-ktx:1.2.5' implementation "androidx.activity:activity-ktx:1.1.0" // Kotlin + coroutines implementation "androidx.work:work-runtime-ktx:2.3.4" // optional - RxJava2 support implementation "androidx.work:work-rxjava2:2.3.4" // optional - GCMNetworkManager support implementation "androidx.work:work-gcm:2.3.4" // optional - Test helpers androidTestImplementation "androidx.work:work-testing:2.3.4" implementation 'org.conscrypt:conscrypt-android:2.2.1'

具体根据需求添加

2.2 请求辅助类

状态管理 enum class Status { SUCCESS, ERROR, LOADING } 请求结果处理类 class Resource<out T>(val status: Status, val data: T?, val message: String?) { companion object { fun <T> success(data: T?) = Resource(Status.SUCCESS, data, null) fun <T> error(msg: String?, data: T?) = Resource(Status.ERROR, data, msg) fun <T> loading(data: T?) = Resource(Status.LOADING, data, null) } }

2.3 使用Retrofit 创建API 接口、接口帮助类

将接口管理和请求放在不同的类文件中,方便管理

API 接口 interface ApiService { @GET("{page}") suspend fun getGirls(@Path("page") page: Int): Girls }

数据类将传到 Demo中

API 接口类调用辅助类 class ApiHelper(private val apiService: ApiService) { suspend fun getGirls() = apiService.getGirls(1) }

2.4 创建Retrofit及OkHttp等网络框架请求帮助类

object ServiceCreator { private val okHttpClient by lazy { OkHttpClient().newBuilder() } private val retrofit: Retrofit by lazy { val builder = Retrofit.Builder() .baseUrl("https://gank.io/api/v2/data/category/Girl/type/Girl/page/1/count/") .addConverterFactory(GsonConverterFactory.create()) val dispatcher = Dispatcher() dispatcher.maxRequests = 1 val httpLoggingInterceptor = HttpLoggingInterceptor() httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.BODY okHttpClient .connectTimeout(10, TimeUnit.SECONDS) .writeTimeout(10, TimeUnit.SECONDS) .readTimeout(10, TimeUnit.SECONDS) .addInterceptor(httpLoggingInterceptor) .addInterceptor(com.kpa.network.data.http.interceptor.HttpLoggingInterceptor()) .dispatcher(dispatcher) builder.client(okHttpClient.build()).build() } fun <T> create(clazz: Class<T>): T = retrofit.create(clazz) inline fun <reified T> createService(clazz: Class<T>): T = create(clazz) }

使用懒加载,将需要的配置在此处配置好,inline 对函数再次调用,可以查一下这样用的优点。

2.5 创建数据仓库

数据仓库的创建是为了能在此处处理数据,可能存在需要存储或者重构的数据,也是将数据的处理和ViewModel分离开,专职做数据处理,ViewModel 做数据周转

class MainRepository(private val apiHelper: ApiHelper) { suspend fun getGirls() = apiHelper.getGirls() }

2.6 ViewModel

一般在使用ViewModel 的时候都是于一个或者一组逻辑相关的页面对应,将数据更加独立、清晰

class MainViewModel(private val mainRepository: MainRepository) : ViewModel() { fun getGirls() = liveData(Dispatchers.IO) { emit(Resource.loading(null)) try { emit(Resource.success(mainRepository.getGirls())) } catch (e: Exception) { emit(Resource.error(e.message, null)) } } }

2.7 创建一个ViewMdoel的工厂,用来创建ViewMdoel

这样做的好处在于可随便传递参数等

class ViewModelFactory(private val apiHelper: ApiHelper) : ViewModelProvider.Factory { override fun <T : ViewModel?> create(modelClass: Class<T>): T { if (modelClass.isAssignableFrom(MainViewModel::class.java)) { return MainViewModel( MainRepository(apiHelper) ) as T } throw IllegalArgumentException("Unknown class name") } }

2.8 创建接口初始化帮助类

清晰的将接口初始化管理在一起,方便查看

object NetWorkHelper { val apiService = ServiceCreator.createService(ApiService::class.java) }

2.9 使用

在Activity、Fragment中 初始化

初始化 mainViewModel = ViewModelProviders.of(this, ViewModelFactory(ApiHelper(NetWorkHelper.apiService))).get(MainViewModel::class.java) 使用数据

清晰的回调状态、处理不同场景

mainViewModel.getGirls().observe(this, Observer { it?.let { resource -> when (resource.status) { Status.SUCCESS -> { recyclerView.visibility = View.VISIBLE progressBar.visibility = View.GONE resource.data?.let { girls -> renderList(girls) } } Status.ERROR -> { progressBar.visibility = View.VISIBLE recyclerView.visibility = View.GONE } Status.LOADING -> { progressBar.visibility = View.VISIBLE Toast.makeText(this, it.message, Toast.LENGTH_LONG).show() } } } })

三、 总结

在开发中上可以更好的接口Databing 等组件、更加优雅的开发,对于数据的处理ViewMdoel 的好处真的太多了,可以多了解一下,

Demo 下载

最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上我搜集整理的2019-2020BAT 面试真题解析,我把大厂面试中常被问到的技术点整理成了【PDF】,包知识脉络 + 诸多细节。

节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

以上内容均放在了开源项目:我的github 中已收录,里面包含不同方向的自学Android路线、面试题集合/面经、及系列技术文章等,资源持续更新中...

最新回复(0)