Retrofit框架的封装流程以及源码分析:
1.Retrofit框架的封装:
01.添加依赖
//Retrofit2的相关依赖
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
//rxjava转换器
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0'
//rxjava相关依赖
implementation 'io.reactivex.rxjava2:rxjava:2.1.1'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
//gson转换
implementation "com.google.code.gson:gson:2.8.5"
// //http请求拦截器Interceptor依赖 -> 依赖无法下载
// implementation('com.github.ihsanbal:LoggingInterceptor:3.0.0') {
// exclude group: 'org.json', module: 'json'
// }
//协程依赖
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0-RC-native-mt'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0-RC-native-mt'
02.添加网络权限
//AndroidManifest.xml中设置网络权限和网络明文访问
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.imooc.retrofitdemo">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
//FIXME 设置可以明文访问网络
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.RetrofitDemo"
android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/network_config">
<activity android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
//设置可以网络明文访问
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
03.自定义观察类MyObserver
//创建一个抽象abstract的观察类,继承生命周期的Observer,泛型就是ResponseBody
//继承RxJava的观察类Observer
abstract class MyObserver: Observer<ResponseBody> {
//请求完成了
override fun onComplete() {
}
//观察者订阅了
override fun onSubscribe(d: Disposable) {
}
//请求成功了
override fun onNext(t: ResponseBody) {
//定义一个抽象类,让子类自己去实现
onSuccess(t.string())
}
//请求出错了
override fun onError(e: Throwable) {
if (e.message!!.contains("401") && e.message!!.contains("Unauthorized")) {
//用户认证到期了 -> 走Session监听器接口中的方法
//用户断网了 -> 走网络监听器接口中的方法
CallManager.onSessionListener?.onReLogin()
return
}
if (e.message != null) {
Log.i("hy55", "e.message==${e.message}")
if (e.message!!.contains("failed to connect to")
|| e.message!!.contains("Failed to connect to")
|| e.message!!.contains("No route to host")
|| e.message!!.contains("timeout")
|| e.message!!.contains("connect timed out")
|| e.message!!.contains("unsupported auth scheme")) {
val am = BaseApplication.getAppContext().getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
if (am.getRunningTasks(1).get(0)?.topActivity != null) {
val cn: ComponentName = am.getRunningTasks(1)?.get(0)?.topActivity!!
//当前不是首页
if (!cn.className.contains("MainActivity")) {
//TODO 直接退出到首页
}
}
return
}
}
//子类自己实现onFailure接口方法
onFailure(e)
}
//抽象abstract方法 -> 请求成功了
abstract fun onSuccess(data: String?)
//抽象abstract方法 —> 请求失败了
abstract fun onFailure(e: Throwable)
}
04.封装Retrofit请求
object RetrofitClient {
const val TAG = "RetrofitClient"
/**
* 设置超时时间
*/
private const val timeOut = 30L
/**
* 创建单例对象,使用@JvmField注解就可以直接使用该参数retrofit,而不是使用Retrofit
*/
@JvmField
var retrofit: Retrofit? = null
/**
* 创建API单例对象:获取其中一条API请求
* 使用@JvmField注解可以直接使用
*/
@JvmField
var requestApi: NewApi? = null
fun initLogin() {
// val httpLoggingInterceptor = LoggingInterceptor.Builder()
// .loggable(BuildConfig.DEBUG)
// .setLevel(Level.BODY)
// .log(Platform.INFO)
// .request("请求")
// .response("响应")
// .build()
val client = OkHttpClient.Builder()
.connectTimeout(5, TimeUnit.SECONDS)
.readTimeout(5, TimeUnit.SECONDS)
.writeTimeout(5, TimeUnit.SECONDS)
.addInterceptor { chain -> //拿到我们的请求
val original = chain.request()
//重新进行build
val builder = original.newBuilder()
//builder立面放入请求头 || 或者放入token
builder.addHeader("Context-Type", "application/json")
val newRequest = builder.build()
chain.proceed(newRequest)
}
.build()
//TODO 设置服务器IP地址
retrofit = Retrofit.Builder()
.client(client)
.baseUrl("http://10.1.1.1:8080/api/")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
//创建请求
if (retrofit != null) {
requestApi = retrofit?.create(NewApi::class.java)
}
}
//创建HTTP请求的API接口方法
interface NewApi {
//这里的Observable是Reactivex的依赖
@POST("account/login")
fun accountLogin(@Body body: RequestBody): Observable<ResponseBody>
//同步请求的API
@POST("account/login")
fun accountSynLogin(@Body body: RequestBody): retrofit2.Call<ResponseBody>
}
}
05.创建同步请求和异步请求
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//使用kotlin-kapt、kotlin-android-extensions可以直接绑定控件
AsynRequestBtn.setOnClickListener {
val loginModel = LoginModel("654321", "123456")
val messageJson = Gson().toJson(loginModel)
Log.i("TAG", "messageJson==$messageJson")
RetrofitClient.let {
it.initLogin()
it.requestApi?.accountLogin(RequestBody.create(MediaType.parse("application/json;charset=UTF-8"), messageJson))
?.subscribeOn(Schedulers.io())
?.observeOn(AndroidSchedulers.mainThread())
?.subscribe(object : MyObserver() {
override fun onSuccess(data: String?) {
Log.i("TAG", "data==$data")
Toast.makeText(this@MainActivity, "成功了", Toast.LENGTH_SHORT).show()
}
override fun onFailure(e: Throwable) {
Log.i("TAG", "e==${e.message}")
Toast.makeText(this@MainActivity, "失败了", Toast.LENGTH_SHORT).show()
}
})
}
}
//TODO: 注意1:添加network_config.xml,设置usesCleartextTraffic为true
//TODO: 注意2:AndroidManifest.xml中添加Internet的相关Permission
SynRequestBtn.setOnClickListener {
//FIXME 不能在主线程中进行同步请求
GlobalScope.launch {
val loginModel = LoginModel("654321", "123456")
val messageJson = Gson().toJson(loginModel)
RetrofitClient.let {
//FIXME 这里的.string()才是获取Response的方法(注意:不是.toString())
//FIXME API请求需要换成同步请求的API(修改返回值为Call<ResponseBody>)
val result = it.requestApi?.accountSynLogin(RequestBody.create(MediaType.parse("application/json;charset=UTF-8"), messageJson))
?.execute()?.body()?.string()
Log.i("TAG", "result==$result")
}
}
}
}
}
2.Retrofit使用实例:
01.同步请求
01.注意:同步请求不能在主线程中进行
02.注意:.execute?.body()?.string()才能获取到ResponseBody的内容
//FIXME 不能在主线程中进行同步请求
GlobalScope.launch {
val loginModel = LoginModel("654321", "123456")
val messageJson = Gson().toJson(loginModel)
RetrofitClient.let {
//FIXME 这里的.string()才是获取Response的方法(注意:不是.toString())
//FIXME API请求需要换成同步请求的API(修改返回值为Call<ResponseBody>)
val result = it.requestApi?.accountSynLogin(RequestBody.create(MediaType.parse("application/json;charset=UTF-8"), messageJson))
?.execute()?.body()?.string()
Log.i("hy55", "result==$result")
}
}
02.异步请求
RetrofitClient.let {
it.initLogin()
it.requestApi?.accountLogin(RequestBody.create(MediaType.parse("application/json;charset=UTF-8"), messageJson))
?.subscribeOn(Schedulers.io())
?.observeOn(AndroidSchedulers.mainThread())
?.subscribe(object : MyObserver() {
override fun onSuccess(data: String?) {
Log.i("hy55", "data==$data")
Toast.makeText(this@MainActivity, "成功了", Toast.LENGTH_SHORT).show()
}
override fun onFailure(e: Throwable) {
Log.i("hy55", "e==${e.message}")
Toast.makeText(this@MainActivity, "失败了", Toast.LENGTH_SHORT).show()
}
})
}