Kotlin使用Coroutine+ViewModel+retrofit构建一个网络请求框架
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构建一个网络请求框架相关推荐
- 一步步搭建Retrofit+RxJava+MVP网络请求框架(二)
在前面已经初步封装了一个MVP的网络请求框架,那只是个雏形,还有很多功能不完善,现在进一步进行封装.添加了网络请求时的等待框,retrofit中添加了日志打印拦截器,添加了token拦截器,并且对Da ...
- 一步步搭建Retrofit+RxJava+MVP网络请求框架(二),个人认为这次封装比较强大了
在前面已经初步封装了一个MVP的网络请求框架,那只是个雏形,还有很多功能不完善,现在进一步进行封装.添加了网络请求时的等待框,retrofit中添加了日志打印拦截器,添加了token拦截器,并且对Da ...
- 一步步搭建Retrofit+RxJava+MVP网络请求框架(二),个人认为这次封装比较强大了...
在前面已经初步封装了一个MVP的网络请求框架,那只是个雏形,还有很多功能不完善,现在进一步进行封装.添加了网络请求时的等待框,retrofit中添加了日志打印拦截器,添加了token拦截器,并且对Da ...
- 如何独立开发一个网络请求框架
(原创出处为本博客:http://www.cnblogs.com/linguanh/) 目录: 前言 准备工作 开发模式 开发原则 线程 高并发 TCP/UDP 本类介绍 开发选择 功能列表 ...
- 一步步搭建Retrofit+RxJava+MVP网络请求框架(一)
首先,展示一下封装好之后的项目的层级结构. 1.先创建一个RetrofitApiService.java package com.xdw.retrofitrxmvpdemo.http;import ...
- Kotlin+Retrofit + MVVM 的网络请求框架的封装
Kotlin 代码我上传了,里面注释写的很详细,大家有什么不懂的可以私信我, 因为文章内容实在是太多了,不想写 代码地址: https://wwp.lanzoum.com/iDOvK0eb0ude 密 ...
- Android 教你一步步搭建MVP+Retrofit+RxJava网络请求框架
目录 1.什么是MVP? 2.什么是Retrofit? 3.RxJava 4.实践 之前公司的项目用到了MVP+Retrofit+RxJava的框架进行网络请求,所以今天特此写一篇文章以做总结.相信很 ...
- App 组件化/模块化之路——如何封装网络请求框架
App 组件化/模块化之路--如何封装网络请求框架 在 App 开发中网络请求是每个开发者必备的开发库,也出现了许多优秀开源的网络请求库.例如 okhttp retrofit android-asyn ...
- android网络请求框架_2020,最新APP重构:网络请求框架
在现在的app,网络请求是一个很重要的部分,app中很多部分都有或多或少的网络请求,所以在一个项目重构时,我会选择网络请求框架作为我重构的起点.在这篇文章中我所提出的架构,并不是所谓的 最好 的网络请 ...
最新文章
- 无线信标功能初步测试
- 原生Android之(6.0及以上)权限申请
- 1、MySQL存储过程是什么?
- php 单一职责原则,Laravel深入学习8 - 单一责任原则
- 中国大学慕课python答案第七章_中国大学慕课mooc用Python玩转数据章节答案
- 漫谈Clustering:高斯混合模型(GMM)
- VRTK实现瞬移, 多场景复制
- 人人商城小程序微信支付配置
- 新天龙官网服务器更新消息,《新天龙八部》1月20日全服更新维护公告
- python中对称差_python 合集set,交集,并集,差集,对称差集别搞混
- 不正经技术研究,键盘侠,你武器可能有个坑!!
- 计算机已达到最大连接数
- 山大华特卧龙学校第一届ACM赛后总结_题目
- Mybatis源码分析: MapperMethod功能讲解
- 庆祝奥运会圆满闭幕!
- 来看看移动端小程序技术的前世今生!小白也能看明白
- 抖音seo源码混剪工具@小程序开发自主挂载
- Java异常转译(exception translation)的使用
- InDesign 教程:如何更改内容颜色?
- Java基础知识面试题汇总