如何在kotlin中正确使用retrofit

第一步:添加retrofit依赖,版本要求2.6.0+,支持协程

//添加retrofit依赖,版本要求2.6.0+,支持协程
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'

第二步:添加 lifecycle viewmodel 依赖

//添加 lifecycle viewmodel 依赖
    def lifecycle_version = "2.2.0"
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"

第三步:创建ApiService 与实体类

/**
 *com.example.kt_cf_project.api
 *Created by LuZhangHui on2021/9/27 16:18
 *describe:
 *18
 */
interface ApiService {
    companion object{
        val BASE_URL =  "http://192.168.31.67:8080/ssm/ws/commRest/"
    }
    //suspend关键字修饰方法,表示这是一个挂起函数,可以在协程中使用,然后返回可以直接返回我们想要的实体类
    这个功能只能在Retrofit 2.6以后的版本中使用
    @GET("login/{login_id}/{password}")
    suspend fun doLogin(@Path("login_id") login_id:String, @Path("password") password : String = "123456") : ResultData<User>
}
data class ResultData<T>(
    val success : Boolean,
    val result : Int,
    val message : String,
    val user: T) {
    companion object{
        const val CODE_SUCCESS = 0
    }

    fun apiData() : T{
        if (result == CODE_SUCCESS) {
            return user
        }else{
            throw (ApiException(result,message))
        }
    }
}
/**
 *com.example.kt_cf_project.mode
 *Created by LuZhangHui on2021/9/27 15:52
 *describe:
 *52
 */
data class User(
    val dept_code: String,
    val depts: List<Dept>,
    val login_id: String,
    val name: String,
    val passwd: String,
    val user_code: String,
    val wards: List<Any>
)

data class Dept(
    val dept_code: String,
    val dept_name: String
)

第四步: 创建Retrofit ,以及提供service服务

/**
 *com.example.kt_cf_project.api
 *Created by LuZhangHui on2021/9/27 16:35
 *describe: 创建Retrofit ,以及提供service服务 devices
 *35
 */
object RetrofitClient {
    val okHttpClient = OkHttpClient.Builder()
        .callTimeout(30,TimeUnit.SECONDS)
        .build()

    val retrofit = retrofit2.Retrofit.Builder()
        .baseUrl(ApiService.BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .client(okHttpClient)
        .build()

    val apiService = retrofit.create(ApiService::class.java)
}

第五步:创建viewModel,执行网络请求

package com.example.kt_cf_project.viewMode

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.kt_cf_project.api.RetrofitClient
import com.example.kt_cf_project.mode.User
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import retrofit2.Response

/**
 *com.example.kt_cf_project.viewMode
 *Created by LuZhangHui on2021/9/27 16:09
 *describe:
 *09
 */
class UserViewMode : ViewModel() {
    val apiData =MutableLiveData<User>()
    val doLoginRepostory by lazy {
        DoLoginRepostory()
    }

    fun dologin(account:String, password:String){
    // 2021/9/27 进行网络请求,登录操作
    
    //GlobalScope是一个*的协程,作用域是全局的,无法提早取消。使用的时候最好使用ViewModel,LiveData,和ViewModel的扩展viewModelScope来完成网络请求
    /*GlobalScope.launch {
            val result = withContext(Dispatchers.IO) { RetrofitClient.apiService.doLogin(account, password).apiData() }

        }*/
        
        /**ViewModel的扩展viewModelScope
         * viewModelScope 是官方提供的ViewModel的扩展,继承CoroutineScope,CoroutineScope字面意思协程作用域,
         * 它会跟踪所有它所创建的协程, 当当前的ViewModel结束的时候,它所执行的异步任务也需要结束,防止内存泄露,
         * 之前我们需要在ViewModel的onCleared方法中通过SupervisorJob的cancel方法来销毁,使用viewModelScope可以简化这个操作,
         * 它会自动调用ViewModel的onCleared取消当前操作
         */
        viewModelScope.launch {
            withContext(Dispatchers.IO){
                try {
//                    val doLogin = doLoginRepostory.doLogin(account, password)
                    apiData.postValue(RetrofitClient.apiService.doLogin(account,password).apiData())
                }catch (e:Exception){
                    e.printStackTrace()
                }
            }
        }
/*        val doLogin = doLoginRepostory.doLogin(account, password)
        doLogin.enqueue(object : Callback, retrofit2.Callback<ResultData<User>> {
            *//**
             * Invoked for a received HTTP response.
             *
             *
             * Note: An HTTP response may still indicate an application-level failure such as a 404 or 500.
             * Call [Response.isSuccessful] to determine if the response indicates success.
             *//*
            override fun onResponse(call: Call<ResultData<User>>, response: Response<ResultData<User>>) {
                apiData.postValue(response?.body()?.apiData())
            }

            *//**
             * Invoked when a network exception occurred talking to the server or when an unexpected exception
             * occurred creating the request or processing the response.
             *//*
            override fun onFailure(call: Call<ResultData<User>>, t: Throwable) {

            }

        })*/
    }

}

第六步:在activity中调用及获取数据

package com.example.kt_cf_project.ui.activity

import android.content.Intent
import android.os.Bundle
import android.text.Editable
import android.text.TextUtils
import android.text.TextWatcher
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import com.example.kt_cf_project.R
import com.example.kt_cf_project.base.BaseActivity
import com.example.kt_cf_project.databinding.ActivityLoginBinding
import com.example.kt_cf_project.viewMode.UserViewMode
import com.google.gson.Gson

class LoginActivity : BaseActivity<ActivityLoginBinding>() {
    val userViewMode by lazy {
        ViewModelProvider(this).get(UserViewMode::class.java)
    }

    var isClickable = false //登录按钮是否可以点击
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        initView()
        initEvent()
    }

    private fun initView() {
        userViewMode.run {
            apiData.observe(this@LoginActivity, Observer {
                logd("userinfo-->"+Gson().toJson(it))
                if (it != null) {
                    startActivity(Intent(this@LoginActivity,MainActivity::class.java))
                }else{
                    toast("登录失败,请稍后重试!")
                }
            })
        }
        binding.emailSignInButton.setOnClickListener {
            userViewMode.dologin(
                account = binding.email.text.toString(),
                password = binding.password.text.toString()
            )
        }
        binding.email.addTextChangedListener(object : TextWatcher{
                override fun afterTextChanged(s: Editable?) {
                    logd("after-->${s.toString()}")

                }

                override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
                    logd("before-->${s.toString()}")
                }

                override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                    logd("onTextChanged-->${s.toString()}")
                    //判断是否有内容 控制登录btn的可点击状态
                    isLoginOk(!TextUtils.isEmpty(s) && !TextUtils.isEmpty(binding.password.text))
                }

        })

        binding.password.addTextChangedListener (object : TextWatcher {
            override fun afterTextChanged(s: Editable?) {

            }

            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {

            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                //判断是否有内容 控制登录btn的可点击状态
                isLoginOk(!TextUtils.isEmpty(s) && !TextUtils.isEmpty(binding.email.text))
            }
        })

    }

    private fun initEvent() {

    }

    fun isLoginOk(isOk: Boolean) {
        logd("isok$isOk")
        if (isClickable == isOk){
            return
        }
        isClickable = isOk
        if (isClickable) {
            binding.emailSignInButton.isClickable = true
            binding.emailSignInButton.setBackgroundResource(R.drawable.selector_btn_blue_bg)
        } else {
            binding.emailSignInButton.isClickable = false
            binding.emailSignInButton.setBackgroundResource(R.drawable.login_btn_unable)
        }
    }
}
上一篇:linq-Distinct2


下一篇:12个View绘制流程高频面试题,retrofit原理