一、添加依赖和网络权限

添加依赖

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. [转帖]优化命令之iotop命令

    文章目录 引言 一.iotop简介 1.iotop安装 2.iotop语法 3.iotop参数 二.I/O的常用快捷键 三.交互模式 四.iotop示例 1.只显示正在产生I/O的进程 2.显示指定P ...

  2. IO调度算法的简单学习与整理

    IO调度算法的简单学习与整理 前言 前几天整理了 /sys/block/sda/queue/nr_requests 以及 /sys/block/sda/device/queue_depth 的两个参数 ...

  3. [转帖]jvm学习三-MAT内存分析工具的使用

    目录 1 模拟内存溢出程序 1.1 jvm配置 1.2 测试代码 2 MAT工具进行内存分析 2.1 大纲介绍 2.2 Histogram视图介绍 2.3 Leak Suspects视图介绍 2.4 ...

  4. dmidecode 查看内存以及硬件信息

    安装工具dmidecode 使用 1.查看内存槽及内存条 $ sudo dmidecode -t memory 2.查看内存的插槽数,已经使用多少插槽.每条内存多大 $ sudo dmidecode  ...

  5. echarts显示地图

    <template> <div class="managingPatientSize"> <div id="china-map"& ...

  6. flutter项目目录介绍

    1 flutter项目目录介绍 android 安卓平台的的相关代理 build 编译后的 ios ios 平台的的相关代理 lib 自己写代码的目录 包好自己的代码 资源 test 放测试文件的 p ...

  7. 【小实验】javascript 能够表述的最大整数

    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 打开浏览器的控制台,开始输入数值: 输入:(16 位十进制 ...

  8. Linux慢 进程kswapd0与events/0消耗大量CPU的问题 一次网站宕机的处理

    今天下午网站宕了两次机,发工单给阿里云,发现原因是服务器的CPU 100%了. 重启服务器后,使用 top 命令看看是哪些进程消耗那么大的 CPU 使用.盯了有好十几分钟,主要消耗 CPU 的进程有两 ...

  9. 修改微信PC通知声音

    安装软件 下载地址如下 点我下载 提取码:1314 找到微信的位置 选择版本号文件夹进去 搜索关键词:WeChatResource.dll 拖拽到软件当中,选择如下分类 118是通知声音 119是来电 ...

  10. Leetcode 92题反转链表 II(Reverse Linked List II) Java语言求解

    前言 反转链表可以先看我这篇文章: Leetcode 206题 反转链表(Reverse Linked List)Java语言求解 题目链接 https://leetcode-cn.com/probl ...