Android Kotlin学习(三)- Retrofit
单例模式
kotlin单例模式实现方式有多种,最简单的直接使用Object,这里使用带有线程安全的方式:
class SingletonDemo private constructor() {
companion object {
val instance: SingletonDemo by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
SingletonDemo() }
}
}
泛型
Kotlin 的泛型也允许在定义类、接口、函数时使用泛型形参,这个泛型形参将在声明变量、创建对象、调用方法时动态地指定
data class BaseResponse<T>(var data:T, var errorCode:Int, var errorMsg:String)
Retrofit封装
import com.kotlin.demo.common.Constant
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Response
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.*
import java.util.concurrent.TimeUnit
class RetrofitUtil {
val BASE_URL = "https://www.wanandroid.com";
var retrofit:Retrofit ?= null;
companion object{
val instance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
RetrofitUtil();
}
}
init {
create();
}
class ReceivedCookiesInterceptor : Interceptor{
override fun intercept(chain: Interceptor.Chain): Response {
var originalResponse = chain.proceed(chain.request());
//这里获取请求返回的cookie
//这里获取请求返回的cookie
if (!originalResponse.headers("Set-Cookie").isEmpty()) {
val cookies: MutableSet<String> = HashSet<String>()
for (header in originalResponse.headers("Set-Cookie")) {
cookies.add(header)
}
MmkvUtil.encodeSet(Constant.MMKV_COOKIE_KEY, cookies)
}
return originalResponse;
}
}
class AddCookiesInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
var builder = chain.request().newBuilder();
val cookie: Set<String> = MmkvUtil.decodeStringSet(Constant.MMKV_COOKIE_KEY);
if (cookie != null) {
for (c in cookie) {
builder.addHeader("Cookie", c)
}
}
return chain.proceed(builder.build());
}
}
fun create():Retrofit?{
var builder = OkHttpClient.Builder();
var httpLoggingInterceptor = HttpLoggingInterceptor();
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
var client = builder.addInterceptor(httpLoggingInterceptor)
.addInterceptor(ReceivedCookiesInterceptor())
.addInterceptor(AddCookiesInterceptor())
.readTimeout(10, TimeUnit.SECONDS)
.connectTimeout(10, TimeUnit.SECONDS)
.retryOnConnectionFailure(true).build();
retrofit = Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create()).client(client).build();
return retrofit;
}
}
MMKV封装(来源网络)
从网上直接找了个MMKV封装的工具类
import android.os.Parcelable
import com.tencent.mmkv.MMKV
object MmkvUtil{
var mv: MMKV? = null
init {
mv=MMKV.defaultMMKV()
}
fun encode(key: String?, `object`: Any) {
when (`object`) {
is String -> {
mv?.encode(key, `object`)
}
is Int -> {
mv?.encode(key, `object`)
}
is Boolean -> {
mv?.encode(key, `object`)
}
is Float -> {
mv?.encode(key, `object`)
}
is Long -> {
mv?.encode(key, `object`)
}
is Double -> {
mv?.encode(key, `object`)
}
is ByteArray -> {
mv?.encode(key, `object`)
}
else -> {
mv?.encode(key, `object`.toString())
}
}
}
fun encodeSet(key: String?, sets: Set<String?>?) {
mv?.encode(key, sets)
}
fun encodeParcelable(key: String?, obj: Parcelable?) {
mv?.encode(key, obj)
}
fun decodeInt(key: String?): Int? {
return mv?.decodeInt(key, 0)
}
fun decodeDouble(key: String?): Double {
return mv?.decodeDouble(key, 0.00)!!
}
fun decodeLong(key: String?): Long {
return mv?.decodeLong(key, 0L)!!
}
fun decodeBoolean(key: String?): Boolean {
return mv?.decodeBool(key, false) == true
}
fun decodeBooleanTure(key: String?, defaultValue: Boolean): Boolean {
return mv?.decodeBool(key, defaultValue) == true
}
fun decodeFloat(key: String?): Float {
return mv?.decodeFloat(key, 0f)!!
}
fun decodeBytes(key: String?): ByteArray {
return mv?.decodeBytes(key)!!
}
fun decodeString(key: String?): String {
return mv?.decodeString(key, "").toString()
}
fun decodeStringDef(key: String?, defaultValue: String): String {
return mv?.decodeString(key, defaultValue).toString()
}
fun decodeStringSet(key: String?): Set<String> {
return mv?.decodeStringSet(key, emptySet()) as Set<String>
}
fun <T : Parcelable?> decodeParcelable(key: String?, tClass: Class<T>?): T? {
return mv?.decodeParcelable(key, tClass)
}
moveKey(key: String?) {
mv?.removeValueForKey(key)
}
fun clearAll() {
mv?.clearAll()
}
}
API接口
import com.kotlin.demo.model.user.LoginResponse
import retrofit2.Call
import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded
import retrofit2.http.POST
interface UserRequest {
@FormUrlEncoded
@POST("user/login")
fun login(
@Field("username") username: String?,
@Field("password") password: String?
): Call<BaseResponse<LoginResponse>>
}
使用实例
open class LoginViewModel() : ViewModel() {
var TAG = "LoginViewModel";
var userLd : MutableLiveData<User> = MutableLiveData<User>();
lateinit var request:UserRequest;
init {
request = RetrofitUtil.instance.retrofit?.create(UserRequest::class.java)!!;
}
fun onLogin(v:View){
Log.i(TAG,"login ${userLd.value?.name} ${userLd.value?.pwd}");
var call = request.login(userLd.value?.name,userLd.value?.pwd);
call.enqueue(object:Callback<BaseResponse<LoginResponse>>{
override fun onResponse(
call: Call<BaseResponse<LoginResponse>>,
response: Response<BaseResponse<LoginResponse>>
) {
Log.i(TAG,"onResponse = "+ (response.body()?.errorCode ?: -10000));
}
override fun onFailure(call: Call<BaseResponse<LoginResponse>>, t: Throwable) {
}
})
}
}