Kotlin使用Coroutine+ViewModel+retrofit构建一个网络请求框架

公司里的老代码用的网络请求框架技术都比较老,为了快速搭建一个网络请求框架,提高工作效率,记录一下用jetpack相关内容搭建一个网络请求框架。

dependencies {implementation 'androidx.core:core-ktx:1.3.2'implementation 'androidx.appcompat:appcompat:1.2.0'implementation 'com.google.android.material:material:1.3.0'implementation 'androidx.constraintlayout:constraintlayout:2.0.4'implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1'implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'testImplementation 'junit:junit:4.+'androidTestImplementation 'androidx.test.ext:junit:1.1.2'androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'def roomVersion = "2.4.1"implementation "androidx.room:room-runtime:$roomVersion"annotationProcessor "androidx.room:room-compiler:$roomVersion"kapt("androidx.room:room-compiler:$roomVersion")implementation "androidx.room:room-ktx:$roomVersion"implementation "androidx.multidex:multidex:2.0.1"//  =============第三方库========================//Retrofit网络请求implementation "com.squareup.retrofit2:retrofit:2.7.0"implementation "com.squareup.retrofit2:converter-gson:2.7.0"// OkHttpimplementation "com.squareup.okhttp3:okhttp:4.2.2"//retrofit的log日志implementation 'com.squareup.okhttp3:logging-interceptor:3.5.0'//Kotlin Coroutines 协程implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2"}

该工程是随便新建的工程,工程中还有Room的使用,所以贴出了所有添加的依赖,重点依然是记录网络框架的搭建。

ApiService

interface ApiService {@GET("wxarticle/chapters/json")suspend fun getWXArticle() : ArticleData
}

ApiFactory

object ApiFactory {private val mClient : OkHttpClient by lazy { newClient() }fun <T> createService(baseUrl:String, clazz: Class<T>): T =Retrofit.Builder().baseUrl(baseUrl).client(mClient).addConverterFactory(GsonConverterFactory.create(GsonBuilder().serializeNulls().create())).build().create(clazz)private fun newClient() = OkHttpClient.Builder().apply{connectTimeout(30,TimeUnit.SECONDS)readTimeout(10,TimeUnit.SECONDS)writeTimeout(10,TimeUnit.SECONDS)addInterceptor(HttpLoggingInterceptor(HttpLog()).setLevel(HttpLoggingInterceptor.Level.BODY))}.build()class HttpLog : HttpLoggingInterceptor.Logger {override fun log(message: String) {Log.d("HttpLogInfo", message)}}
}

NetworkService

object NetworkService {private const val BASE_URL = "https://www.wanandroid.com/"val api by lazy { ApiFactory.createService(BASE_URL, ApiService::class.java) }
}

Repository

object Repository {private suspend fun <T : BaseBean> preprocessData(baseBean: T, context: Context? = null): T =if (baseBean.errorCode == 0) {// 成功// 返回数据baseBean} else {// 失败// 抛出接口异常throw ApiException(baseBean.errorCode, baseBean.errorMsg)}suspend fun getWXArticle(): ArticleData =NetworkService.api.getWXArticle().let {preprocessData(it)}
}

common文件下工具类

ApiException

class ApiException(val errorCode: Int,val msg: String):Throwable(msg)

ExceptionUtil

object ExceptionUtil {/*** 处理异常,toast提示错误信息*/fun catchException(e: Throwable) {e.printStackTrace()when (e) {is HttpException -> {catchHttpException(e.code())return}is SocketTimeoutException -> showToast(R.string.common_error_net_time_out)is UnknownHostException, is NetworkErrorException -> showToast(R.string.common_error_net)is MalformedJsonException, is JsonSyntaxException -> showToast(R.string.common_error_server_json)// 接口异常is ApiException -> showToast(e.msg,e.errorCode)else -> showToast("${MyApplication.instance.getString(R.string.common_error_do_something_fail)}:${e::class.java.name}")}}/*** 处理网络异常*/fun catchHttpException(errorCode: Int) {if (errorCode in 200 until 300) return// 成功code则不处理showToast(catchHttpExceptionCode(errorCode), errorCode)}/*** toast提示*/private fun showToast(@StringRes errorMsg: Int, errorCode: Int = -1) {showToast(MyApplication.instance.getString(errorMsg), errorCode)}/*** toast提示*/private fun showToast(errorMsg: String, errorCode: Int = -1) {if (errorCode == -1) {ToastUtils.showShort(errorMsg)} else {ToastUtils.showShort("$errorCode:$errorMsg")}}/*** 处理网络异常*/private fun catchHttpExceptionCode(errorCode: Int): Int = when (errorCode) {in 500..600 -> R.string.common_error_serverin 400 until 500 -> R.string.common_error_requestelse -> R.string.common_error_request}
}

string内容

 <string name="common_error_net">网络异常,请检查网络连接!</string><string name="common_error_net_time_out">网络超时</string><string name="common_error_do_something_fail">操作异常</string><string name="common_error_request">请求错误</string><string name="common_error_server">服务器错误</string><string name="common_error_server_json">服务器错误:Json格式错误</string>

ToastUtils

object ToastUtils {fun showShort(msg: String){Toast.makeText(MyApplication.instance,msg,Toast.LENGTH_SHORT).show()}
}

扩展viewmodel方法

fun ViewModel.launch(block : suspend CoroutineScope.() -> Unit,onError: (e:Throwable) -> Unit,onComplete : () -> Unit = {}
){viewModelScope.launch(CoroutineExceptionHandler { _, throwable ->run{ExceptionUtil.catchException(throwable)onError(throwable)}}) {try {block.invoke(this)}finally {onComplete()}}
}

BaseViewModel

abstract class BaseViewModel : ViewModel(){val loadState = MutableLiveData<LoadState>()
}

新建bean文件下,包含三个文件
ArticleData非固定,根据需求新建,此处只为展示例子

class ArticleData : BaseBean() {var data = arrayListOf<Chapters>()
}class Chapters{//    children: []
//    courseId: 13
//    id: 408
//    name: "鸿洋"
//    order: 190000
//    parentChapterId: 407
//    userControlSetTop: false
//    visible: 1var courseId = ""var id = ""var name =  ""var order = 0
}

BaseBean
该类格式根据平台返回的结构改变

open class BaseBean{var errorCode:Int = -1var errorMsg:String = ""
}

LoadState

/*** 加载状态* @author ssq* sealed 关键字表示此类仅内部继承*/
sealed class LoadState(val msg: String) {/*** 加载中*/class Loading(msg: String = ""): LoadState(msg)/*** 成功*/class Success(msg: String = ""): LoadState(msg)/*** 失败*/class Fail(msg: String = ""): LoadState(msg)
}

总体结构如图所示

具体使用
MainViewModel

class MainViewModel : BaseViewModel() {val data = MutableLiveData<ArticleData>()fun getData() = launch({loadState.value = LoadState.Loading()data.value = Repository.getWXArticle()loadState.value = LoadState.Success()},{loadState.value = LoadState.Fail()})
}

MainFragment

class MainFragment : Fragment() {companion object {fun newInstance() = MainFragment()}private lateinit var viewModel: MainViewModelprivate var binding: MainFragmentBinding? = nulloverride fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View {binding = MainFragmentBinding.inflate(inflater, container, false)return binding!!.root}override fun onActivityCreated(savedInstanceState: Bundle?) {super.onActivityCreated(savedInstanceState)viewModel = ViewModelProvider(this).get(MainViewModel::class.java)binding?.btGetData?.setOnClickListener {viewModel.getData()}activity?.let { it ->viewModel.data.observe(it, Observer { showdata(it) })viewModel.loadState.observe(it, Observer { changeLoadState(it) })}}private fun changeLoadState(loadState: LoadState){binding?.pbProgress?.visibility = when(loadState){is LoadState.Loading -> {binding?.tvData?.text = ""View.VISIBLE}else -> View.GONE}}private fun showdata(data: ArticleData){binding?.tvData?.text= "id: ${data.data[0].id}  name: ${data.data[0].name}"}}

补充MyApplication,根据需求决定是否需要

class MyApplication : MultiDexApplication(){companion object{lateinit var instance:MyApplicationvar isDebugMode = false}override fun onCreate() {super.onCreate()instance = thisif("com.example.com.viewmodeltest" == getProcessName(this, android.os.Process.myPid())){initDebug()}}private fun initDebug() {isDebugMode = instance.applicationInfo != null && instance.applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE != 0}private fun getProcessName(cxt: Context, pid: Int): String {//获取ActivityManager对象val am = cxt.getSystemService(Context.ACTIVITY_SERVICE)if (am is ActivityManager) {//在运行的进程val runningApps = am.runningAppProcessesfor (processInfo in runningApps) {if (processInfo.pid == pid) {return processInfo.processName}}}return ""}
}

xml很简单,一个button,一个progress,一个TextView

参考资料网址:https://blog.csdn.net/NJP_NJP/article/details/103524778
https://github.com/sange93/MVVMDemo

Kotlin使用Coroutine+ViewModel+retrofit构建一个网络请求框架相关推荐

  1. 一步步搭建Retrofit+RxJava+MVP网络请求框架(二)

    在前面已经初步封装了一个MVP的网络请求框架,那只是个雏形,还有很多功能不完善,现在进一步进行封装.添加了网络请求时的等待框,retrofit中添加了日志打印拦截器,添加了token拦截器,并且对Da ...

  2. 一步步搭建Retrofit+RxJava+MVP网络请求框架(二),个人认为这次封装比较强大了

    在前面已经初步封装了一个MVP的网络请求框架,那只是个雏形,还有很多功能不完善,现在进一步进行封装.添加了网络请求时的等待框,retrofit中添加了日志打印拦截器,添加了token拦截器,并且对Da ...

  3. 一步步搭建Retrofit+RxJava+MVP网络请求框架(二),个人认为这次封装比较强大了...

    在前面已经初步封装了一个MVP的网络请求框架,那只是个雏形,还有很多功能不完善,现在进一步进行封装.添加了网络请求时的等待框,retrofit中添加了日志打印拦截器,添加了token拦截器,并且对Da ...

  4. 如何独立开发一个网络请求框架

    (原创出处为本博客:http://www.cnblogs.com/linguanh/) 目录:   前言 准备工作  开发模式 开发原则 线程 高并发 TCP/UDP 本类介绍  开发选择 功能列表 ...

  5. 一步步搭建Retrofit+RxJava+MVP网络请求框架(一)

    首先,展示一下封装好之后的项目的层级结构.  1.先创建一个RetrofitApiService.java package com.xdw.retrofitrxmvpdemo.http;import ...

  6. Kotlin+Retrofit + MVVM 的网络请求框架的封装

    Kotlin 代码我上传了,里面注释写的很详细,大家有什么不懂的可以私信我, 因为文章内容实在是太多了,不想写 代码地址: https://wwp.lanzoum.com/iDOvK0eb0ude 密 ...

  7. Android 教你一步步搭建MVP+Retrofit+RxJava网络请求框架

    目录 1.什么是MVP? 2.什么是Retrofit? 3.RxJava 4.实践 之前公司的项目用到了MVP+Retrofit+RxJava的框架进行网络请求,所以今天特此写一篇文章以做总结.相信很 ...

  8. App 组件化/模块化之路——如何封装网络请求框架

    App 组件化/模块化之路--如何封装网络请求框架 在 App 开发中网络请求是每个开发者必备的开发库,也出现了许多优秀开源的网络请求库.例如 okhttp retrofit android-asyn ...

  9. android网络请求框架_2020,最新APP重构:网络请求框架

    在现在的app,网络请求是一个很重要的部分,app中很多部分都有或多或少的网络请求,所以在一个项目重构时,我会选择网络请求框架作为我重构的起点.在这篇文章中我所提出的架构,并不是所谓的 最好 的网络请 ...

最新文章

  1. 无线信标功能初步测试
  2. 原生Android之(6.0及以上)权限申请
  3. 1、MySQL存储过程是什么?
  4. php 单一职责原则,Laravel深入学习8 - 单一责任原则
  5. 中国大学慕课python答案第七章_中国大学慕课mooc用Python玩转数据章节答案
  6. 漫谈Clustering:高斯混合模型(GMM)
  7. VRTK实现瞬移, 多场景复制
  8. 人人商城小程序微信支付配置
  9. 新天龙官网服务器更新消息,《新天龙八部》1月20日全服更新维护公告
  10. python中对称差_python 合集set,交集,并集,差集,对称差集别搞混
  11. 不正经技术研究,键盘侠,你武器可能有个坑!!
  12. 计算机已达到最大连接数
  13. 山大华特卧龙学校第一届ACM赛后总结_题目
  14. Mybatis源码分析: MapperMethod功能讲解
  15. 庆祝奥运会圆满闭幕!
  16. 来看看移动端小程序技术的前世今生!小白也能看明白
  17. 抖音seo源码混剪工具@小程序开发自主挂载
  18. Java异常转译(exception translation)的使用
  19. InDesign 教程:如何更改内容颜色?
  20. Java基础知识面试题汇总

热门文章

  1. 【Linux】:shell循环语句
  2. 男人四十一枝花,我花开后百花杀!Orz..繁忙的工作之余,joke一下~~
  3. 简单易懂!!shell循环语句!for、while、until
  4. ThoughtWork培训感想
  5. PHP实战——开发遇到过的错误问题与解决方案汇总
  6. 直播APP开发技术原理分享
  7. 开源 chatgpt 项目私有化部署
  8. HIVE HSQL 基本操作命令
  9. AOD实践,modis数据下载,modis数据处理
  10. Java基础03运算符