kotlin中使用协程Coroutines和retrofit2.6以上搭建MVVM架构

效果图

在这里插入图片描述
全文链接

使用的依赖版本

  • 同时启用databinding
 dataBinding {
        enabled true
    }
    
    
 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.2.0"
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.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"
  • 创建view model
  • 现用方式
//      创建view model
        netViewModel = ViewModelProvider(this).get(NetViewMoudle::class.java)
  • 废弃过时方式 ViewModelProviders is desprecated
//        netViewModel = ViewModelProviders.of(this).get(NetViewMoudle::class.java)

retrofit封装类

package com.wjx.android.wanandroidmvvm.base.https

import android.util.Log
import com.example.myapp.common.Constant
import com.example.myapp.common.SPreference
import com.google.gson.Gson
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import java.lang.StringBuilder
import java.util.concurrent.TimeUnit

/**
 * @Author yangtianfu
 * @CreateTime 2020/4/1 21:17
 * @Describe  retrofit封装类
 */
class RetrofitFactory private constructor() {
    private val retrofit: Retrofit


    init {

        val gson = Gson().newBuilder()
            .setLenient()
            .serializeNulls()
            .create()

        retrofit = Retrofit.Builder()
            .baseUrl("https://www.wanandroid.com/")
            .client(initOkhttpClient())
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build()

    }


    companion object {
        val instance: RetrofitFactory by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
            RetrofitFactory()
        }

    }


    private fun initOkhttpClient(): OkHttpClient {

        val okHttpClient = OkHttpClient.Builder()
            .connectTimeout(5, TimeUnit.SECONDS)
            .readTimeout(5, TimeUnit.SECONDS)
            .addInterceptor(initLogInterceptor())
            .build()


        return okHttpClient
    }


    /*
    * 日志拦截器
    * */
    private fun initLogInterceptor(): HttpLoggingInterceptor {

        val interceptor = HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
            override fun log(message: String) {
                Log.i("Retrofit", message)
            }
        })

        interceptor.level = HttpLoggingInterceptor.Level.BODY

        return interceptor
    }


    /*
    * 具体服务实例化
    * */
    fun <T> getService(service: Class<T>): T {

        return retrofit.create(service)
    }
}

网络相关数据结构

  • 返回数据最外层包装
package com.example.myapp.bean

/**
 * @Author yangtianfu
 * @CreateTime 2020/4/1 18:08
 * @Describe 返回数据最外层包装
 */


data class BaseResp<T> (
    var errorCode: Int = 0,
    var errorMsg: String = "",
    var data: T
)
  • 单个数据结构
package com.example.myapp.bean

/**
 * @Author yangtianfu
 * @CreateTime 2020/4/1 18:13
 * @Describe 单个数据返回实体类
 */
data class WBean(
    val apkLink: String,
    val audit: Int,
    val author: String,
    val canEdit: Boolean,
    val chapterId: Int,
    val chapterName: String,
    val collect: Boolean,
    val courseId: Int,
    val desc: String,
    val descMd: String,
    val envelopePic: String,
    val fresh: Boolean,
    val id: Int,
    val link: String,
    val niceDate: String,
    val niceShareDate: String,
    val origin: String,
    val prefix: String,
    val projectLink: String,
    val publishTime: Long,
    val selfVisible: Int,
    val shareDate: Long,
    val shareUser: String,
    val superChapterId: Int,
    val superChapterName: String,
    val tags: List<Any>,
    val title: String,
    val type: Int,
    val userId: Int,
    val visible: Int,
    val zan: Int
)
  • 数据顶层声明文件,全局的方法
package com.example.myapp.ext

import com.example.myapp.bean.BaseResp

/**
 * @Author yangtianfu
 * @CreateTime 2020/4/1 19:59
 * @Describe  数据解析扩展函数 顶层声明 作用域为package
 */

fun <T> BaseResp<T>.dataConvert(): T {
    if (errorCode == 0) {
        return data
    } else {
        throw Exception(errorMsg)
    }
}

/**
 * 全局toast
 */
fun Context.toast(msg: String) {
    Toast.makeText(this, msg,  LENGTH_SHORT).show()
}

/**
 * 全局跳转
 */
fun Activity.openActivity(cls: Class<*>) {
    startActivity(Intent(this, cls))
}

定义协程api

package com.wjx.android.wanandroidmvvm.base.https

import com.example.myapp.bean.BaseResp
import com.example.myapp.bean.WBean
import retrofit2.http.GET

/**
 * @Author yangtianfu
 * @CreateTime 2020/3/31 21:04
 * @Describe retrofit 使用协程定义api
 */

interface ApiService {

    /**
     * 使用协程进行网络请求
     */
    @GET("article/top/json/")
    suspend fun getTopArticle(): BaseResp<List<WBean>>


    @GET("article/list/{page}/json")
    suspend fun getArticleList(@Path("page") page: Int = 0): Result<PageEntity<Article>>

}

ViewModel层

package com.example.myapp.moudle

import android.util.Log
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.myapp.bean.WBean
import com.example.myapp.ext.dataConvert
import com.wjx.android.wanandroidmvvm.base.https.ApiService
import com.wjx.android.wanandroidmvvm.base.https.RetrofitFactory
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.lang.Exception
import kotlin.math.log

/**
 * @Author yangtianfu
 * @CreateTime 2020/4/1 19:18
 * @Describe 自带生命周期的viewmoudle
 */
class NetViewMoudle :ViewModel() {
//   vm持有数据层引用,并利用livedata赋值更新UI
    var list= MutableLiveData<List<WBean>>()

    /**
     * viewModelScope是一个绑定到当前viewModel的作用域  当ViewModel被清除时会自动取消该作用域,所以不用担心内存泄漏为问题
     */
    fun getTopArticle(){
        viewModelScope.launch {
            try {
                //withContext表示挂起块  配合Retrofit声明的suspend函数执行 该块会挂起直到里面的网络请求完成 最后一行就是返回值
                val data = withContext(Dispatchers.IO){
                    //dataConvert扩展函数可以很方便的解析出我们想要的数据  接口很多的情况下下可以节省不少无用代码
                    RetrofitFactory.instance.getService(ApiService::class.java).getTopArticle().dataConvert()
                }
                //给LiveData赋值  ui会自动更新
                list.value = data
            }catch (e:Exception){
                e.printStackTrace()
                Log.e("net error","网络请求错误${e.toString()}")
            }
        }
    }
}
class ArticleViewModel :ViewModel() {
    private val _articleListData = MutableLiveData<List<Article>>()
    //保证外部只能观察此数据,不同通过setValue修改 model调用articleListData拿到网络请求数据交个观察者,但是不能修改
    val articleListData: LiveData<List<Article>> = _articleListData

    private val _errorMsg = MutableLiveData<String?>()
    val errorMsg: LiveData<String?> = _errorMsg

    fun fetch(page:Int){
        viewModelScope.launch {
            var result = RetrofitFactory.instance.getService(ApiService::class.java).getArticleList(page)
            //请求到的数据用livedata包裹
            _articleListData.value = result.data.datas
        }


    }
}

UI层调用

package com.example.myapp.ui

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProviders
import com.example.myapp.R
import com.example.myapp.bean.Animal
import com.example.myapp.databinding.ActivityMainBinding
import com.example.myapp.moudle.NetViewMoudle
import com.example.myapp.vm.AnimalViewModel
import com.google.gson.Gson
import com.wjx.android.wanandroidmvvm.base.https.ApiService
import com.wjx.android.wanandroidmvvm.base.https.RetrofitFactory
import kotlinx.android.synthetic.main.activity_main.*
import kotlin.jvm.java as java

class MainActivity : AppCompatActivity() {
    lateinit var mBinding:ActivityMainBinding
    lateinit var mViewMode:AnimalViewModel

    lateinit var netViewModel:NetViewMoudle
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mBinding = DataBindingUtil.setContentView<ActivityMainBinding>(this,R.layout.activity_main)
        var animal = Animal("dog",0)
        mViewMode = AnimalViewModel(animal)
        mBinding.model = mViewMode //model指代xml xml中 name="model"的VM对象

//      创建view model
//        netViewModel = ViewModelProviders.of(this).get(NetViewMoudle::class.java)
        netViewModel = ViewModelProvider(this).get(NetViewMoudle::class.java)

//        请求网络
        mBinding.listener = View.OnClickListener {
            when(it.id){
                R.id.btn ->  netViewModel.getTopArticle()
            }
        }
//        数据变化更新UI,livedata的数据被观察
        netViewModel.list.observe(this, Observer {
            tv.text = Gson().toJson(it)
        })

    }


}

   //观察文章列表数据
        viewModel.articleListData.observe(this, Observer { list ->
            //articleListData 的值改变时触发此监听
            loadProgress.visibility = View.GONE
            adapter.submitList(list)
        })
        viewModel.errorMsg.observe(this, Observer {
            if (it!=null){
                toast(it)
            }
        })
  • github地址:
  • https://github.com/BlissYang91/kotlin
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值