一、添加依赖和网络权限

添加依赖

implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0' // 可选
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.3'
  • 第一条依赖是下载Retrofit、OkHttp和Okio这几个库,我们就不需要手动引入OkHttp库了;
  • 第二条依赖是一个Retrofit的转换库,它是借助GSON来解析JSON数据的,所以也会将GSON库一起下载;
  • 第三条是 okHttp 的日志拦截器相关,可选。

添加网络权限

AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"/>

二、Retrofit data api 部分封装

2.1 创建接收服务器返回数据类、异常类、异常码

通用返回数据类

import com.google.gson.annotations.SerializedName

data class CommonResponse<T>(
@SerializedName("code") val code: Int = -1, @SerializedName("data") val data: T, @SerializedName("msg") val msg: String
) {
fun isSuccess(): Boolean {
return code == 0
}
}

异常类

data class ResponseException(
var code: Int, override var message: String?
) : RuntimeException(message)

异常码定义

import androidx.annotation.IntDef

@IntDef(
ErrorCode.SUCCESS, // 成功
ErrorCode.FAIL, // 失败
ErrorCode.NETWORK_EXCEPTION,//无网络,网络连接异常
ErrorCode.HOST_ERROR,//host异常
ErrorCode.TIMEOUT,//超时
ErrorCode.CANCEL,//取消
ErrorCode.JSON_SYNTAX_EXCEPTION,//数据解析异常
ErrorCode.OK,//请求正常
ErrorCode.CREATED,
ErrorCode.FORBIDDEN,
ErrorCode.UNAUTHORIZED,//无授权
ErrorCode.NOT_FOUND,
ErrorCode.OTHER,//其他错误,目前还未关注和处理的
ErrorCode.CUSTOM_FIRST,//自定义,可自行修改
ErrorCode.VALUE_IS_NULL//空值
)
@Retention(AnnotationRetention.SOURCE)
annotation class ErrorCode {
companion object {
const val SUCCESS = 0
const val FAIL = 1
const val NETWORK_EXCEPTION = 2
const val HOST_ERROR = 3
const val TIMEOUT = 4
const val CANCEL = 5
const val JSON_SYNTAX_EXCEPTION = 6
const val OK = 200
const val CREATED = 201
const val FORBIDDEN = 401
const val UNAUTHORIZED = 402
const val NOT_FOUND = 404
const val OTHER = 509
const val CUSTOM_FIRST = 600
const val VALUE_IS_NULL = CUSTOM_FIRST + 1
}
}

2.2 封装异常处理

import com.google.gson.JsonSyntaxException
import retrofit2.HttpException
import java.net.ConnectException
import java.net.SocketException
import java.net.SocketTimeoutException
import java.net.UnknownHostException private const val TAG = "getResultOrNull" suspend fun <T> getResultOrNull(block: suspend () -> CommonResponse<T>): T? {
runCatching {
block()
}.onSuccess {
return it.data
}.onFailure {
when (it) {
is ResponseException -> {
logW(TAG, "getResult exception, code: ${it.code} message: ${it.message}")
}
is UnknownHostException,
is HttpException,
is ConnectException,
is SocketTimeoutException,
is SocketException,
is NumberFormatException,
is IllegalArgumentException,
is IllegalStateException,
is JsonSyntaxException -> {
logW(TAG, "getResult exception: ${it.message}")
}
else -> {
logW(TAG, "getResult other exception: ${it.message}")
}
}
return null
}
return null
}

2.3 定义 SSLSocketClient

import java.security.KeyManagementException
import java.security.KeyStore
import java.security.NoSuchAlgorithmException
import java.security.SecureRandom
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import javax.net.ssl.* object SSLSocketClient { @Throws(NoSuchAlgorithmException::class, KeyManagementException::class)
fun getSSLSocketFactory(): SSLSocketFactory {
val sslContext = SSLContext.getInstance("TLS")
sslContext.init(null, getTrustManager(), SecureRandom())
return sslContext.socketFactory
} private fun getTrustManager(): Array<TrustManager> {
val trustManager: X509TrustManager = object : X509TrustManager {
@Throws(CertificateException::class)
override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {
} @Throws(CertificateException::class)
override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {
} override fun getAcceptedIssuers(): Array<X509Certificate> {
return arrayOf()
}
}
return arrayOf(trustManager)
} fun getHostnameVerifier(): HostnameVerifier {
return HostnameVerifier { _, _ -> true }
} @Throws(Exception::class)
fun getX509TrustManager(): X509TrustManager {
var trustManager: TrustManager? = null
val trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
trustManagerFactory.init(null as? KeyStore)
val trustManagers = trustManagerFactory.trustManagers
if (trustManagers.size != 1 || trustManagers[0] !is X509TrustManager) {
throw IllegalStateException("Unexpected default trust managers: $trustManagers")
}
return trustManagers[0] as X509TrustManager
}
}

2.4 自定义 CustomGsonConverterFactory

import com.google.gson.Gson
import com.google.gson.JsonIOException
import com.google.gson.TypeAdapter
import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonToken
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.ResponseBody
import okio.Buffer
import retrofit2.Converter
import retrofit2.Retrofit
import java.io.ByteArrayInputStream
import java.io.InputStreamReader
import java.io.OutputStreamWriter
import java.lang.reflect.Type
import java.nio.charset.Charset
import kotlin.text.Charsets.UTF_8 class CustomGsonConverterFactory private constructor(val gson: Gson): Converter.Factory() {
companion object {
fun create(): CustomGsonConverterFactory {
return create(Gson())
} private fun create(gson: Gson?): CustomGsonConverterFactory {
if (gson == null) throw NullPointerException("gson == null")
return CustomGsonConverterFactory(gson)
}
} override fun responseBodyConverter(
type: Type,
annotations: Array<out Annotation>,
retrofit: Retrofit
): Converter<ResponseBody, *> {
return CustomGsonResponseBodyConverter(gson, gson.getAdapter(TypeToken.get(type)))
} override fun requestBodyConverter(
type: Type,
parameterAnnotations: Array<out Annotation>,
methodAnnotations: Array<out Annotation>,
retrofit: Retrofit
): Converter<*, RequestBody> {
return CustomGsonRequestBodyConverter(gson, gson.getAdapter(TypeToken.get(type)))
}
} private class CustomGsonRequestBodyConverter<T>(private val gson: Gson, private val adapter: TypeAdapter<T>) : Converter<T, RequestBody> {
private val MEDIA_TYPE = "application/json; charset=UTF-8".toMediaTypeOrNull()
private val UTF_8 = Charset.forName("UTF-8") override fun convert(value: T): RequestBody {
val buffer = Buffer()
val writer = OutputStreamWriter(buffer.outputStream(), UTF_8)
val jsonWriter = gson.newJsonWriter(writer)
adapter.write(jsonWriter, value)
jsonWriter.close()
return buffer.readByteString().toRequestBody(MEDIA_TYPE)
}
} private class CustomGsonResponseBodyConverter<T>(private val gson: Gson, private val adapter: TypeAdapter<T>) : Converter<ResponseBody, T> {
override fun convert(value: ResponseBody): T {
val response = value.string()
val commonResponse = gson.fromJson(response, CommonResponse::class.java)
/** 先将code与msg解析出来,code非0的情况下直接抛ApiException异常,这样我们就将这种异常交给onFailure()处理了**/
if (!commonResponse.isSuccess()) {
value.close()
throw ResponseException(commonResponse.code, commonResponse.msg)
}
val contentType = value.contentType()
val charset = contentType?.charset(UTF_8) ?: UTF_8
val inputStream = ByteArrayInputStream(response.toByteArray())
val reader = InputStreamReader(inputStream, charset)
val jsonReader = gson.newJsonReader(reader) value.use { _ ->
val result = adapter.read(jsonReader)
if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
throw JsonIOException("JSON document was not fully consumed.")
}
return result
}
}
}

2.5 创建 RetrofitClient 以及业务接口

object RetrofitClient {
private val instance: Retrofit by lazy {
val logger = HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BASIC } val client = OkHttpClient.Builder()
.addInterceptor(logger)
.addInterceptor(Interceptor { chain ->
val originalRequest: Request = chain.request()
val request = originalRequest.newBuilder()
.header("content-type", "application/json;charset:utf-8")
.build()
chain.proceed(request)
})
.sslSocketFactory(SSLSocketClient.getSSLSocketFactory(), SSLSocketClient.getX509TrustManager())
.connectTimeout(20, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build() Retrofit.Builder().baseUrl(HttpUrls.getBaseUrl())
.client(client)
.addConverterFactory(CustomGsonConverterFactory.create())
.build()
} // TestService 见下
fun getTestService(): TestService {
return instance.create(TestService::class.java)
}
}

三、具体业务接口封装

3.1 data 部分定义

IDataSource

interface IDataSource {
suspend fun getPrivacyList(): List<PrivacyInfo>
}

TestService

interface TestService {
@POST("privacy/getPrivacyList")
suspend fun getPrivacyList(@Body req: GetPrivacyReq): CommonResponse<List<PrivacyInfo>>
}

RemoteDataSource

class RemoteDataSource private constructor() : IDataSource {

    private lateinit var testService: TestService

    companion object {
@Volatile
private var instance: RemoteDataSource? = null fun getInstance(context: Context): RemoteDataSource {
return instance ?: synchronized(this) {
instance ?: RemoteDataSource().also {
it.testService = RetrofitClient.getTestService()
instance = it
}
}
}
} override suspend fun getPrivacyList(): List<PrivacyInfo> = withContext(Dispatchers.IO) {
val req = buildGetPrivacyReq() // 创建入参
val result = getResultOrNull {
testService.getPrivacyList(req)
}
result?: mutableListOf()
} }

TestRepository

object TestRepository {
private val localDataSource: LocalDataSource by lazy {
LocalDataSource.getInstance(App.appContext)
} private val remoteDataSource: RemoteDataSource by lazy {
RemoteDataSource.getInstance(App.appContext)
} suspend fun getPrivacyList(): List<PrivacyInfo> {
return remoteDataSource.getPrivacyList()
}
}

Retrofit 的基本用法的更多相关文章

  1. RxJava + Retrofit完成网络请求

    1.前言 本文基于RxJava.Retrofit的使用,若是对RxJava或Retrofit还不了解的简友可以先了解RxJava.Retrofit的用法再来看这篇文章. 在这片文章之前分别单独介绍过R ...

  2. Android Retrofit RxJava实现缓存

    RxJava如何与Retrofit结合参考:http://blog.csdn.net/jdsjlzx/article/details/52015347 缓存配置 app网络数据的离线缓存实现有很多种办 ...

  3. 源码分析Retrofit请求流程

    Retrofit 是 square 公司的另一款广泛流行的网络请求框架.前面的一篇文章<源码分析OKHttp执行过程>已经对 OkHttp 网络请求框架有一个大概的了解.今天同样地对 Re ...

  4. 从Retrofit的源码来看 HTTP

    关于Retrofit是啥,这里就不多解释了,还是先来瞅下官网: 而这次主要是了解它的底层动作机制,而在了解底层之前先来回顾一下官网的整体使用步骤: 咱们也以官网的这个例子为例,先从简单的使用开始逐步深 ...

  5. Retrofit全攻略——进阶篇

    最近事比较多,距离上次写文章已经过去了一个月了.上一篇文章Retrofit全攻略——基础篇 介绍了Retrofit的基础用法,这篇文章介绍点进阶的用法. 打印网络日志 在开发阶段,为了方便调试,我们需 ...

  6. 2. Retrofit2 -- Basic Authentication on Android

    2. Retrofit2 -- Basic Authentication on Android android Retrofit tutorial 整合基本的认证 Retrofit 1.9 Retro ...

  7. 1. Retrofit2 -- Getting Started and Create an Android Client

    1. Retrofit2 -- Getting Started and Create an Android Client Retrofit tutorial 什么是 Retrofit 如何申明请求 准 ...

  8. android电子书App、自定义图表、仿腾讯漫画App、仿淘宝优惠券、3D选择容器等源码

    Android精选源码 仿支付宝记账本功能,饼状图:数字键盘 android一款功能完善的电子书应用源码 Android自定义图标库,使用方便,扩展性强 android 3D立体无限旋转容器源码 an ...

  9. android retrofit @Query用法

    http://www.b3a4a.com/?id=71 //https://login.xx.cn/mobile/login?access_token=A7E3D8CC98776F7C16F328B6 ...

  10. retrofit post请求多文件,partMap用法

    1. APIService 定义注解 @Multipart @POST("cyxx/Feedback/add.do") Observable<ResponseBody> ...

随机推荐

  1. redis 6源码解析之 事件

    redis的事件分为:文件事件和时间事件.文件事件是基于I/O的事务处理,时间事件则是基于时间点的事务处理.redis事件支持的多路复用包含四个实现:ae_epoll.c,ae_evport.c,ae ...

  2. Concat、Push、Spread syntax性能差异对比

    今天在力扣上做了一道数组扁平化的题,按理来说,应该熟能生巧了,但是在使用concat时候超出了时间限制,使用push可以通过,代码如下: /** * @describe 使用concat,超出时间限制 ...

  3. 在K8S中,Pod生命周期包含哪些?

    在Kubernetes(简称K8s)中,Pod的生命周期经历了一系列状态变化.以下是Pod可能处于的一些主要状态: Pending: 当创建一个Pod时,它首先会进入Pending状态.这个状态下,K ...

  4. 每日一库:Memcache

    Memcache 是一个高性能.分布式的内存缓存系统,常用于缓存数据库查询结果.API调用结果.页面内容等,以提升应用程序的性能和响应速度.下面详细介绍一些 Memcache 的特点和使用方式: 内存 ...

  5. Git的使用(二):远程仓库

    在github上创建远程仓库 本地创建Git仓库适合自己一个人完成工程,但是实际情况中我们需要其他人来协作开发,此时就可以把本地仓库同步到远程仓库,同时还增加了本地仓库的一个备份.常用的远程仓库就是g ...

  6. 从零开始配置vim(28)——DAP 配置

    首先给大家说一声抱歉,前段时间一直在忙换工作的事,包括但不限于交接.背面试题准备面试.好在最终找到了工作,也顺利入职了.期间也有朋友在催更,在这里我对关注本系列的朋友表示感谢.多的就不说了,我们正式进 ...

  7. 从零开始配置vim(24)——自动补全

    neovim 自带的代码补全的效果并不好,而且它分为好多类,如果需要人为的去判断使用路径补全.使用当前buffer中的单词补全.亦或者使用include 来进行补全,那样使用起来就很不方便了.针对代码 ...

  8. 金融领域:产业链知识图谱包括上市公司、行业和产品共3类实体,构建并形成了一个节点10w+,关系边16w的十万级别产业链图谱

    金融领域:产业链知识图谱包括上市公司.行业和产品共3类实体,构建并形成了一个节点10w+,关系边16w的十万级别产业链图谱 包括上市公司所属行业关系.行业上级关系.产品上游原材料关系.产品下游产品关系 ...

  9. C++ CryptoPP使用RSA加解密

    Crypto++ (CryptoPP) 是一个用于密码学和加密的 C++ 库.它是一个开源项目,提供了大量的密码学算法和功能,包括对称加密.非对称加密.哈希函数.消息认证码 (MAC).数字签名等.C ...

  10. Json Schema高性能.net实现库 LateApexEarlySpeed.Json.Schema - 直接从code生成json schema validator

    LateApexEarlySpeed.Json.Schema - Json schema validator generation from code 除了用户手动传入标准的json schema来生 ...