OkHttp3 超級(jí)簡(jiǎn)單實(shí)用封裝

本人分成了四個(gè)類,其實(shí)可以更加精簡(jiǎn),兩個(gè)類足以

已封裝可直接引用
DLTool: 基礎(chǔ)項(xiàng)目框架:OkHttp封裝、仿微信位置選擇等 (gitee.com)

implementation 'com.gitee.toune.DLTool:DLHttp:v1.3.1'//網(wǎng)絡(luò)請(qǐng)求框架
  1. 首先引入依賴 okhttp github地址
    implementation("com.squareup.okhttp3:okhttp:4.9.0")

  2. 上代碼,首先展示一下請(qǐng)求代碼(Kotlin)

  DLHttp.post("url")  //請(qǐng)求地址和請(qǐng)求方式,get和post方式切換
            .add(map)   //參數(shù)可以直接傳入map集合
            .add("key","value")  //參數(shù)也可以傳入鍵值對(duì)
            .add(Object)  //參數(shù)也可以類對(duì)象
            .build(object : HttpCallBack<T>() { //傳入返回的實(shí)體類
                override fun success(t: T?) {
                          //得到返回的實(shí)體類
                }
                override fun error(code:Int,err: String?) {
                          //得到錯(cuò)誤信息提醒
                }
            })

以上就是請(qǐng)求示例代碼,夠簡(jiǎn)單了吧,當(dāng)然這都是表面的,下面來看一下背后做的工作

  1. 上關(guān)鍵類 DLHttp :
package com.toune.dltools.http

import android.util.Log
import com.tamsiree.rxkit.RxFileTool
import okhttp3.*
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONException
import org.json.JSONObject
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.net.URLConnection
import java.util.concurrent.TimeUnit
import kotlin.collections.ArrayList
import kotlin.collections.HashMap

/**
 * @Author Dong Lei
 * @Date 2020/12/16 0016-下午 12:35
 * @Info 描述:網(wǎng)絡(luò)請(qǐng)求
 */
class DLHttp {
    companion object {
        private var dlHttp: DLHttp? = null

        /**
         * 初始化
         */
        fun instance() {
            dlHttp = DLHttp()
        }

        /**
         * 獲取client
         */
        private fun getHttpClient() {
            if (dlHttp != null) {
                if (dlHttp!!.dlHttpClient == null) {
                    dlHttp!!.dlHttpClient = OkHttpClient.Builder()
                        .connectTimeout(30, TimeUnit.MINUTES)
                        .readTimeout(30, TimeUnit.MINUTES)
                        .callTimeout(30, TimeUnit.MINUTES)
                        .build()
                }
            }
        }

        /**
         * post請(qǐng)求
         * @param url String? 地址
         * @return DLHttp
         */
        fun post(url: String?): DLHttp {
            instance()
            getHttpClient()
            dlHttp!!.REQUEST_METHOD = dlHttp!!.REQUEST_POST
            dlHttp!!.requestUrl = url
            return dlHttp!!
        }

        /**
         * put請(qǐng)求
         * @param url String? 地址
         * @return DLHttp
         */
        fun put(url: String?): DLHttp {
            instance()
            getHttpClient()
            dlHttp!!.REQUEST_METHOD = dlHttp!!.REQUEST_PUT
            dlHttp!!.requestUrl = url
            return dlHttp!!
        }

        /**
         * get請(qǐng)求
         * @param url String?
         * @return DLHttp
         */
        fun get(url: String?): DLHttp {
            instance()
            getHttpClient()
            dlHttp!!.REQUEST_METHOD = dlHttp!!.REQUEST_GET
            dlHttp!!.requestUrl = url
            return dlHttp!!
        }


        /**
         * 下載文件
         * @param realURL String?
         * @param destFileDir String?
         * @return DLHttp
         */
        fun downFile(realURL: String?, destFileDir: String?): DLHttp {
            instance()
            getHttpClient()
            dlHttp!!.downUrl = realURL
            dlHttp!!.filrDir = destFileDir
            return dlHttp!!
        }
    }

    private val REQUEST_POST = 1001 //post請(qǐng)求
    private val REQUEST_GET = 1002  //get請(qǐng)求
    private val REQUEST_PUT = 1003  //put請(qǐng)求
    private var REQUEST_METHOD = REQUEST_GET //默認(rèn)請(qǐng)求方式GET


    private val JSON_TYPE = 301  //JSON格式提交
    private val FILE_TYPE = 302  //提交文件
    private val FORM_TYPE = 303  //表單提交
    private var BUILD_TYPE = FORM_TYPE //默認(rèn)表單提交


    private var dlHttpClient: OkHttpClient? = null
    private var requestUrl: String? = null

    private var downUrl: String? = null
    private var filrDir: String? = null
    private var downFileName = ""


    private val JSONType: MediaType =
        "application/json; charset=utf-8".toMediaTypeOrNull()!! //JSON的mediaType表頭
    private var requestBody: RequestBody? = null
    private var request: Request? = null

    /**
     * 請(qǐng)求header
     */
    private var headers = Headers.Builder()

    /**
     * json實(shí)體類
     */
    private var jsonObj: Any? = null

    /**
     * 參數(shù)
     */
    private var params: MutableMap<String, Any?> = HashMap()

    /**
     * 文件參數(shù)
     */
    private val files: MutableList<File> = ArrayList()

    fun addHeader(map: Map<String, Any?>): DLHttp {
        for (entry in map) {
            headers.add(entry.key, entry.value.toString())
        }
        return this
    }

    fun addHeader(key: String, value: Any): DLHttp {
        headers.add(key, value.toString())
        return this
    }

    /**
     * 添加單一參數(shù)
     * @param key String
     * @param value Any
     * @return DLHttp
     */
    fun add(key: String, value: Any): DLHttp {
        params[key] = value.toString()
        return this
    }

    /**
     * 添加參數(shù)集合
     * @param map Map<String, Any?>
     * @return DLHttp
     */
    fun add(map: Map<String, Any?>): DLHttp {
        params.putAll(map)
        return this
    }

    /**
     * 添加參數(shù)類
     * @param map Map<String, Any?>
     * @return DLHttp
     */
    fun add(jsonObj: Any): DLHttp {
        this.jsonObj = jsonObj
        return this
    }


    /**
     * 添加文件參數(shù)
     * @param key String
     * @param file File
     * @return DLHttp
     */
    fun add(key: String, file: File): DLHttp {
        files.add(file)
        return this
    }

    /**
     * 以JSON的方式提交數(shù)據(jù)
     * @param dlhttpCallBack IDLHttpCallBack<T>
     */
    fun <T> buildByJson(dlhttpCallBack: IDLHttpCallBack<T>) {
        BUILD_TYPE = JSON_TYPE
        build<T>(dlhttpCallBack)
    }

    /**
     * 基于http的文件上傳(傳入文件數(shù)組和key)混合參數(shù)和文件請(qǐng)求
     * 通過addFormDataPart可以添加多個(gè)上傳的文件
     */
    fun <T> buildByFile(myDataCallBack: IDLHttpCallBack<T>) {
        val multipartBody: MultipartBody.Builder = MultipartBody.Builder()
        multipartBody.setType(MultipartBody.FORM)
        for (key in params.keys) {
            multipartBody.addFormDataPart(key, params[key].toString())
        }
        if (jsonObj != null) {
            multipartBody.addPart(GsonBinder.toJsonStr(jsonObj).toRequestBody(JSONType))
        }
        var fileBody: RequestBody? = null
        for ((index, file) in files.withIndex()) {
            val fileName = file.name
            fileBody = file.asRequestBody(guessMimeType(fileName).toMediaTypeOrNull())
            multipartBody.addFormDataPart("file$index", fileName, fileBody)
        }
        requestBody = multipartBody.build()
        BUILD_TYPE = FILE_TYPE
        build<T>(myDataCallBack)
    }

    /**
     * 獲取文件提交的guessMimeType
     * @param fileName String
     * @return String
     */
    private fun guessMimeType(fileName: String): String {
        val fileNameMap = URLConnection.getFileNameMap()
        var contentTypeFor = fileNameMap.getContentTypeFor(fileName)
        if (contentTypeFor == null) {
            contentTypeFor = "application/octet-stream"
        }
        return contentTypeFor
    }


    fun <T> build(dlHttpCallBack: IDLHttpCallBack<T>) {
        //使用默認(rèn)header
        for (entry in IBaseCallBack.headerMap) {
            headers.add(entry.key, entry.value.toString())
        }
        //開始請(qǐng)求
        dlHttpCallBack.Builder().startH()
        //數(shù)據(jù)上傳方式
        when (BUILD_TYPE) {
            JSON_TYPE -> {
                if (jsonObj != null) {
                    requestBody = GsonBinder.toJsonStr(jsonObj).toRequestBody(JSONType)
                } else if (params.isNotEmpty()) {
                    requestBody = GsonBinder.toJsonStr(params).toRequestBody(JSONType)
                }
            }
            FILE_TYPE -> {
            }
            FORM_TYPE -> {
                //form表單提交
                val builder: FormBody.Builder = FormBody.Builder()
                for (key in params.keys) {
                    builder.add(key, params[key].toString())
                }
                requestBody = builder.build()
            }
        }
        //數(shù)據(jù)上傳方式
        when (REQUEST_METHOD) {
            REQUEST_GET -> {
                val urlBuilder: HttpUrl.Builder = requestUrl!!.toHttpUrlOrNull()!!.newBuilder()
                for (key in params.keys) {
                    urlBuilder.addQueryParameter(key, params[key].toString())
                }
                request = Request.Builder()
                    .url(urlBuilder.build())
                    .headers(headers.build())
                    .get()
                    .build()
            }
            REQUEST_POST -> {
                request = Request.Builder()
                    .url(requestUrl!!)
                    .headers(headers.build())
                    .post(requestBody!!)
                    .build()
            }
            REQUEST_PUT -> {
                request = Request.Builder()
                    .url(requestUrl!!)
                    .headers(headers.build())
                    .put(requestBody!!)
                    .build()
            }
        }
        val call: okhttp3.Call = dlHttpClient!!.newCall(request!!)
        call.enqueue(object : Callback {
            //請(qǐng)求錯(cuò)誤
            override fun onFailure(call: Call, e: IOException) {
                dlHttpCallBack.Builder().errorH(-1, e.message)
            }

            //請(qǐng)求結(jié)果
            override fun onResponse(call: Call, response: Response) {
                try {
                    dlHttpCallBack.Builder().respenseH(response)
                    var jsonStr: String = response.body!!.string()
                    Log.e("urlAndJson:${response.request.url}", jsonStr)
                    if (response.code == 200) {
                        dlHttpCallBack.Builder()
                            .successH(GsonBinder.toObj(jsonStr, dlHttpCallBack.mType))
                        return
                    }
                    val baseObj = JSONObject(jsonStr)
                    if (baseObj != null) {
                        when (baseObj!!.getInt(IBaseCallBack.codeStr)) {
                            IBaseCallBack.SUCCESS_CODE -> {
                                if (DLHttpConfig.useDefaultStr) {
                                    val iBaseCallBack = GsonBinder.toObj(
                                        baseObj.getString(IBaseCallBack.dataStr),
                                        IBaseCallBack::class.java
                                    )
                                    dlHttpCallBack.Builder().successH(iBaseCallBack!!.data as T)
                                } else {
                                    dlHttpCallBack.Builder()
                                        .successH(GsonBinder.toObj(jsonStr, dlHttpCallBack.mType))
                                }
                            }
                            IBaseCallBack.ERROR_CODE -> {
                                dlHttpCallBack.Builder()
                                    .errorH(
                                        baseObj.getInt(IBaseCallBack.codeStr),
                                        baseObj.getString(IBaseCallBack.msgStr)
                                    )
                            }
                            IBaseCallBack.TOKEN_ERROR_CODE -> {
                                dlHttpCallBack.Builder()
                                    .tokenErrorH(baseObj.getString(IBaseCallBack.msgStr))
                            }
                            else -> {
                                dlHttpCallBack.Builder()
                                    .errorH(
                                        baseObj.getInt(IBaseCallBack.codeStr),
                                        baseObj.getString(IBaseCallBack.msgStr)
                                    )
                            }
                        }
                    } else {
                        dlHttpCallBack.Builder().successH(jsonStr as T)
                    }
                    dlHttpCallBack.Builder().infoH(baseObj.getString(IBaseCallBack.msgStr))
                    response.close()
                    dlHttpCallBack.Builder().endH()
                } catch (e: JSONException) {
                    e.printStackTrace()
                    Log.e("urlAndJson:", "$response.request.url,${e.message}")
                    dlHttpCallBack.Builder().errorH(-2, "網(wǎng)絡(luò)開小差,請(qǐng)稍后重試")
                    dlHttpCallBack.Builder().endH()
                }
            }
        })
    }

    /**
     * 下載文件******************************************************************************************************************************************
     */
    /**
     * 文件下載
     *
     * @param url path路徑
     * @param destFileDir 本地存儲(chǔ)的文件夾路徑
     * @param myDataCallBack 自定義回調(diào)接口
     */
    private var downCall: Call? = null
    private val totalSize = 0L //APK總大小

    private val downloadSize = 0L // 下載的大小

    private val count = 0f //下載百分比


    fun down(httpFileCallBack: IDLHttpFileCallBack) {
        val request: Request = Request.Builder()
            .url(downUrl!!)
            .build()
        downCall = dlHttpClient!!.newCall(request)
        downCall!!.enqueue(object : Callback {
            override fun onResponse(call: Call, response: Response) {
                when (response.code) {
                    200 -> {
                        var `is`: InputStream? = null
                        val buf = ByteArray(2048)
                        var len = 0
                        var fos: FileOutputStream? = null
                        // 儲(chǔ)存下載文件的目錄
                        val dir: File = File(filrDir)
                        if (!dir.exists()) {
                            dir.mkdirs()
                        }
                        RxFileTool.createFileByDeleteOldFile(dir.toString() + downFileName)
                        var updateFile = RxFileTool.getFileByPath("$dir/$downFileName")
                        try {
                            `is` = response.body!!.byteStream()
                            val total: Long = response.body!!.contentLength()
                            httpFileCallBack.Builder().startH(total)
                            fos = FileOutputStream(updateFile)
                            var sum: Long = 0
                            while (`is`.read(buf).also { len = it } != -1) {
                                fos!!.write(buf, 0, len)
                                sum += len.toLong()
                                httpFileCallBack.Builder().progressH(sum)
                            }
                            fos!!.flush()
                            fos.close()
                            httpFileCallBack.Builder().successH(updateFile)
                        } catch (e: Exception) {
                            httpFileCallBack.Builder().errorH("下載失敗")
                        } finally {
                            try {
                                `is`?.close()
                            } catch (e: IOException) {
                            }
                            try {
                                fos?.close()
                            } catch (e: IOException) {
                                e.printStackTrace()
                            }
                        }
                    }
                    else -> {
                        httpFileCallBack.Builder().errorH("下載失敗")
                    }
                }
            }

            override fun onFailure(call: Call, e: IOException) {
                httpFileCallBack.Builder().errorH(e.message)
            }
        })
    }

    private fun getFileName(url: String?): String? {
        val separatorIndex = url!!.lastIndexOf("/")
        return if (separatorIndex < 0) url else url.substring(separatorIndex + 1, url.length)
    }


    fun cancelDownload() {
        if (downCall != null) {
            downCall!!.cancel()
        }
    }

}

這個(gè)類中,我做了符合我們項(xiàng)目的深度配置,但是大部分項(xiàng)目都差不多,所以如果需要適配你們的項(xiàng)目只需要修改
TIM截圖20190803101224.png

這個(gè)部分就可以了

  1. 上配置類 IBaseCallBack,根據(jù)你項(xiàng)目的結(jié)構(gòu)進(jìn)行成功code,錯(cuò)誤code,已經(jīng)token過期code的值的修改,還有字段名稱的修改
/**
 * @Author Dong Lei
 * @Date 2020/12/16 0016-下午 14:35
 * @Info 描述:
 */
class IBaseCallBack<T> {
    companion object {
        val headerMap = HashMap<String, Any>()
        var SUCCESS_CODE = 1
        var ERROR_CODE = 0
        var TOKEN_ERROR_CODE = 2001
        var codeStr = "code"   //code對(duì)應(yīng)的字段對(duì)應(yīng)名
        var msgStr = "message" //Message對(duì)應(yīng)的字段對(duì)應(yīng)名
        var dataStr = "data"    //data對(duì)應(yīng)的字段對(duì)應(yīng)名
        var loginVoStr = ""     //登錄返回的數(shù)據(jù)
    }

    var data: T? = null
    var msg: String? = null
    var code: Int = 0
}

5.返回接口類,可以在這里面修改需要實(shí)現(xiàn)的方法

package com.toune.dltools.http

import android.annotation.SuppressLint
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.Message
import com.google.gson.internal.`$Gson$Types`
import com.tamsiree.rxkit.view.RxToast
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type

abstract class IDLHttpCallBack<T> {
    var mType: Type? = null
   open fun start() {}
    abstract fun success(t: T)
    open fun error(code: Int, err: String?) {
        RxToast.error(err!!)
    }

    open fun tokenError(err: String?) {
    }

    open fun info(info: String) {}
    open fun end() {}

    init {
        //Type是 Java 編程語言中所有類型的公共高級(jí)接口。它們包括原始類型、參數(shù)化類型、數(shù)組類型、類型變量和基本類型。
        val superclass = javaClass.genericSuperclass
        mType = if (superclass is Class<*>) {
            null
        } else {
            //ParameterizedType參數(shù)化類型,即泛型
            val parameterized = superclass as ParameterizedType?
            //getActualTypeArguments獲取參數(shù)化類型的數(shù)組,泛型可能有多個(gè)
            //將Java 中的Type實(shí)現(xiàn),轉(zhuǎn)化為自己內(nèi)部的數(shù)據(jù)實(shí)現(xiàn),得到gson解析需要的泛型
            `$Gson$Types`.canonicalize(parameterized!!.actualTypeArguments[0])
        }
    }


    public inner class Builder {

        fun startH() {
            handler.sendEmptyMessage(START)
        }

        fun errorH(code: Int, err: String?) {
            val message = Message()
            val bundle = Bundle()
            bundle.putInt("code", code)
            bundle.putString("msg", err)
            message.obj = bundle
            message.what = ERROR
            handler.sendMessage(message)
        }

        fun successH(data: T?) {
            var message = Message()
            message.obj = data
            message.what = SUCCESS
            handler.sendMessage(message)
        }

        fun endH() {
            handler.sendEmptyMessage(END)
        }

        fun tokenErrorH(string: String) {
            val message = Message()
            message.obj = string
            message.what = TOKEN_ERROR
            handler.sendMessage(message)
        }

        fun infoH(string: String) {
            val message = Message()
            message.obj = string
            message.what = INFO
            handler.sendMessage(message)
        }

        @SuppressLint("HandlerLeak")
        var handler: Handler = object : Handler(Looper.getMainLooper()) {
            override fun handleMessage(msg: Message) {
                when (msg.what) {
                    START -> start()
                    SUCCESS -> success(msg.obj as T)
                    ERROR -> {
                        if (msg.obj != null) {
                            val bundle = msg.obj as Bundle
                            error(bundle.getInt("code"), bundle.getString("msg"))
                        }
                        end()
                    }
                    TOKEN_ERROR -> {
                        //token出錯(cuò)
                        if (msg.obj != null) {
                            tokenError(msg.obj.toString())
                        }
                        end()
                    }
                    END -> end()
                    INFO -> info(msg.obj as String)
                }
            }
        }
        val START = 10001 //請(qǐng)求開始
        val SUCCESS = 10002 //請(qǐng)求成功
        val ERROR = 10003   //請(qǐng)求出錯(cuò)
        val END = 10004 //請(qǐng)求結(jié)束
        val INFO = 10005 //token出錯(cuò)
        val TOKEN_ERROR = 10006 //token出錯(cuò)
    }
}
  1. 為了更清晰,我把文件下載做了單獨(dú)的返回
package com.toune.dltools.http

import android.annotation.SuppressLint
import android.os.Handler
import android.os.Looper
import android.os.Message
import java.io.File

/**
 * 下載文件返回
 */
abstract class IDLHttpFileCallBack {
    abstract fun start(toatleSize: Int)
    abstract fun progress(size: Int)
    abstract fun success(file: File?)
    abstract fun error(err: String?)
   open fun end() {}

    inner class Builder{
        fun errorH(err: String?) {
            val message = Message()
            message.obj = err
            message.what = FILE_ERROR
            fileHandler.sendMessage(message)
        }

        fun startH(total: Long) {
            var message = Message()
            message.obj = total.toInt()
            message.what = FILE_START
            fileHandler.sendMessage(message)
        }

        fun progressH(sum: Long) {
            // 下載中更新進(jìn)度條
            var message = Message()
            message = Message()
            message.obj = sum.toInt()
            message.what = FILE_PROGRESS
            fileHandler.sendMessage(message)
        }

        fun successH(file: File?) {
            // 下載完成
            var message = Message()
            message = Message()
            message.obj = file
            message.what = FILE_SUCCESS
            fileHandler.sendMessage(message)
        }

        var fileHandler: Handler = @SuppressLint("HandlerLeak")
        object : Handler(Looper.getMainLooper()) {
            override fun handleMessage(msg: Message) {
                when (msg.what) {
                    FILE_START -> start(msg.obj as Int)
                    FILE_PROGRESS -> progress(msg.obj as Int)
                    FILE_SUCCESS -> success(msg.obj as File)
                    FILE_ERROR -> {
                        if (msg.obj != null) {
                            error(msg.obj.toString())
                        }
                        end()
                    }
                    FILE_END -> end()
                }
            }
        }
        private val FILE_START = 100001
        private val FILE_SUCCESS = 100002
        private val FILE_ERROR = 100003
        private val FILE_END = 100004
        private val FILE_PROGRESS = 100005
    }
}

GsonBinder類

 package com.toune.dltools.http

import android.text.TextUtils
import com.google.gson.*
import com.google.gson.reflect.TypeToken
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
import java.util.*
import kotlin.jvm.Throws

/**
 * Created by Administrator on 2018/1/11 0011.
 */
object GsonBinder {
    //定義并配置gson
    private val gson: Gson = GsonBuilder() //建造者模式設(shè)置不同的配置
        .serializeNulls() //序列化為null對(duì)象
        .setDateFormat("yyyy-MM-dd HH:mm:ss") //設(shè)置日期的格式
        .disableHtmlEscaping() //防止對(duì)網(wǎng)址亂碼 忽略對(duì)特殊字符的轉(zhuǎn)換
        .registerTypeAdapter(String::class.java, StringConverter()) //對(duì)為null的字段進(jìn)行轉(zhuǎn)換
        .create()

    /**
     * 對(duì)解析數(shù)據(jù)的形式進(jìn)行轉(zhuǎn)換
     *
     * @param obj 解析的對(duì)象
     * @return 轉(zhuǎn)化結(jié)果為json字符串
     */
    fun toJsonStr(obj: Any?): String {
        return if (obj == null) {
            ""
        } else try {
            gson.toJson(obj)
        } catch (e: Exception) {
            ""
        }
    }

    /**
     * 解析為一個(gè)具體的對(duì)象
     *
     * @param json 要解析的字符串
     * @param obj  要解析的對(duì)象
     * @param <T>  將json字符串解析成obj類型的對(duì)象
     * @return
    </T> */
    fun <T> toObj(json: String?, obj: Class<T>?): T? {
        //如果為null直接返回為null
        return if (obj == null || TextUtils.isEmpty(json)) {
            null
        } else try {
            gson.fromJson(json, obj)
        } catch (e: Exception) {
            null
        }
    }

    /**
     * @return 不區(qū)分類型 傳什么解析什么
     */
    fun <T> toObj(jsonStr: String?, type: Type?): T? {
        var t: T? = null
        try {
            t = gson.fromJson(jsonStr, type)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return t
    }

    /**
     * 將Json數(shù)組解析成相應(yīng)的映射對(duì)象列表
     * 解決類型擦除的問題
     */
    fun <T> toList(jsonStr: String?, clz: Class<T>): List<T> {
        var list: List<T> = gson.fromJson(jsonStr, type(clz))
        if (list == null) list = ArrayList()
        return list
    }

    fun <T> toMap(jsonStr: String?, clz: Class<T>): Map<String?, T> {
        var map: Map<String?, T> = gson.fromJson(jsonStr, type(clz))
        if (map == null) map = HashMap()
        return map
    }

    fun toMap(jsonStr: String?): Map<String, Any> {
        val type: Type = object : TypeToken<Map<String?, Any?>?>() {}.type
        return gson.fromJson(jsonStr, type)
    }

    private class type(private val type: Type) : ParameterizedType {
        override fun getActualTypeArguments(): Array<Type> {
            return arrayOf(type)
        }

        override fun getRawType(): Type {
            return ArrayList::class.java
        }

        override fun getOwnerType(): Type? {
            return null
        }
    }

    /**
     * 實(shí)現(xiàn)了 序列化 接口    對(duì)為null的字段進(jìn)行轉(zhuǎn)換
     */
    internal class StringConverter : JsonSerializer<String?>, JsonDeserializer<String?> {
        //字符串為null 轉(zhuǎn)換成"",否則為字符串類型
        @Throws(JsonParseException::class)
        override fun deserialize(
            json: JsonElement,
            typeOfT: Type?,
            context: JsonDeserializationContext?
        ): String {
            return json.getAsJsonPrimitive().getAsString()
        }

        override fun serialize(
            src: String?,
            typeOfSrc: Type?,
            context: JsonSerializationContext?
        ): JsonElement {
            return if (src == null || src == "null") JsonPrimitive("") else JsonPrimitive(src.toString())
        }
    }
}

GsonBinder類需要引用 implementation 'com.google.code.gson:gson:2.8.5'
以上就是全部代碼了,第一次寫文章,文字?jǐn)⑹龊捅磉_(dá)有不到位的地方,還請(qǐng)見諒,有問題可以留言

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 我們敲代碼總是離不開網(wǎng)絡(luò)請(qǐng)求。網(wǎng)絡(luò)請(qǐng)求就是想服務(wù)器請(qǐng)求數(shù)據(jù),一般請(qǐng)求到的數(shù)據(jù)就是我們列表上要展示數(shù)據(jù)的數(shù)據(jù)源?,F(xiàn)在...
    Android_HMH閱讀 5,442評(píng)論 0 3
  • Retrofit Retrofit是Square公司開發(fā)的一款針對(duì)Android網(wǎng)絡(luò)請(qǐng)求的框架,Retrofit2...
    Reathin閱讀 1,831評(píng)論 1 11
  • rxjava+retrofit+okhttp3 一:項(xiàng)目簡(jiǎn)介 重所周知 當(dāng)下最流行的網(wǎng)絡(luò)請(qǐng)求的框架非rxjava+...
    高先生single閱讀 2,348評(píng)論 1 5
  • 前言 剛?cè)肼毿鹿?,?fù)責(zé)其Android App的開發(fā),他們的接口訪問是通過SOAP協(xié)議實(shí)現(xiàn)的(基于xml數(shù)據(jù)格式...
    Mersens閱讀 14,644評(píng)論 54 79
  • 活動(dòng)名稱:《胡蘿卜種子》 適用年齡:小班組 繪本分析: 一個(gè)小男孩種下了一顆胡蘿卜種子,然后耐心地等待著,悉心地照...
    za吖閱讀 2,223評(píng)論 0 0

友情鏈接更多精彩內(nèi)容