1. 程式人生 > 程式設計 >詳解Android專案多服務端介面適配(超簡單)

詳解Android專案多服務端介面適配(超簡單)

現狀

Android專案如果是多服務端介面時,一般怎麼弄呢?

方法1:伺服器地址放在Header中

把伺服器地址放在介面Header中,然後通過攔截器來動態修改請求地址而實現的。除了預設伺服器的介面,其它都要加一個Header,有點麻煩。看起來也不爽,不簡潔。

interface ApiHeaderCase {
  /************************** server A ****************************/
  @Headers("host:$SERVER_HOST_A")
  @GET("user/loginWithScanCode")
  fun aMethod1(@Query("id") id: Int): Observable<ResponseBody>

  /************************** server B ****************************/
  @Headers("host:$SERVER_HOST_B")
  @GET("user/loginWithScanCode")
  fun bMethod1(@Query("id") id: Int): Observable<ResponseBody>
}

方法2:多套服務類,例項化為多個物件,準確查詢介面歸屬服務

定義多個類,每個類定義一套服務介面。然後分別例項化為多個物件,再使用準確的物件來呼叫介面。這種方法執行效率是最高的,但是在開發時,可能無法快速知道介面歸屬與哪個服務,需要檢視程式碼才能準確知曉,可以說是少了程式碼提示能力。

interface ApiA {
  @GET("user/loginWithScanCode")
  fun methodA(@Query("id") id: Int): Observable<ResponseBody>
}

interface ApiB {
  @GET("user/loginWithScanCode")
  fun methodB(@Query("id") id: Int): Observable<ResponseBody>
}

方法3:全寫在一起,例項化為多個物件,準確呼叫方法

把所有介面都寫在一個類中,然後根據服務地址分別例項化為多個物件。再準確呼叫方法,為了保證準確呼叫方法,可以給每個介面加個服務名的字首,以減少方法調錯的問題。

interface ApiAllInOne {
  /************************** server A ****************************/
  @GET("user/loginWithScanCode")
  fun aMethod1(@Query("id") id: Int): Observable<ResponseBody>

  /************************** server B ****************************/
  @GET("user/loginWithScanCode")
  fun bMethod1(@Query("id") id: Int): Observable<ResponseBody>
}

const val SERVER_HOST_A = "https://www.a.com/"
const val SERVER_HOST_B = "https://www.b.com/"
fun getApi(retrofit: Retrofit,host: String): ApiAllInOne {
  return retrofit.newBuilder()
      .baseUrl(host).build()
      .create(ApiAllInOne::class.java)
}

fun showNomalUseCase(retrofit: Retrofit) {
  val apiA = getApi(retrofit,SERVER_HOST_A)//save as single instance for repeated usage
  apiA.aMethod1(1).subscribe()
  apiA.bMethod1(1).subscribe()//invalid usage,but no compile error

  val apiB = getApi(retrofit,SERVER_HOST_B)
  apiB.bMethod1(1).subscribe()
  apiB.aMethod1(1).subscribe()//invalid usage,but no compile error
}

有更簡單的方法嗎?

當然有了,而且超方便!

定義介面

(建議)在一個KT檔案中定義所有介面,方便查詢和維護。

interface ApiHolder : ApiA,ApiB

  @BaseUrl("https://www.a.com/")
  interface ApiA {
    @GET("user/loginWithScanCode")
    fun methodA(@Query("id") id: Int): Observable<ResponseBody>
  }

  @BaseUrl("https://www.b.com/")
  interface ApiB {
    @GET("user/loginWithScanCode")
    fun methodB(@Query("id") id: Int): Observable<ResponseBody>
  }

建工具類

一般都需要個工具類的,方便配置攔截器等。如果沒有自定義的需求,也可以直接例項化來用。

可以重寫invokeApi方法,全域性給每個Observable設定執行緒。

class ApiUtil : ApiHolderUtil<ApiHolder>(ApiHolder::class) {
  companion object {
    val apiUtil = ApiUtil()
    val api = apiUtil.api
  }

  override fun invokeApi(api: Any,method: Method,args: Array<*>?): Any {
    val observable = super.invokeApi(api,method,args) as Observable<*>
    return observable.subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
  }
}

動態更新服務地址

還可以動態更新服務地址,比如實現測試服務和正式服務間切換。

//update api baseUrl when needed
  apiUtil.updateApi(ApiA::class,https://www.a2.com/)

呼叫介面

api.methodA(1).subscribe()
  api.methodB(1).subscribe()

引入依賴

dependencies {
  implementation 'com.github.DonaldDu:ApiHolder:x.x.x'//JitPack version
}

該專案使用的三方庫

  • OkHttp3
  • Retrofit2
  • rxjava3(可以修改為rxjava2)
api 'com.squareup.okhttp3:okhttp:4.7.2'
  api "com.squareup.retrofit2:retrofit:2.9.0"
  api "com.squareup.retrofit2:converter-gson:2.9.0"
  api "com.squareup.retrofit2:adapter-rxjava3:2.9.0"
  api 'io.reactivex.rxjava3:rxandroid:3.0.0'

其它說明

rxjava3 ->rxjava2

可以根據需要調整為rxjava2,建議用最新的。

//重寫ApiHolderUtil如下方法,RxJava3CallAdapterFactory ->RxJava2CallAdapterFactory即可。
  protected open fun getRetrofit(client: OkHttpClient): Retrofit {
    return Retrofit.Builder()
        .validateEagerly(validateEagerly)
        .addConverterFactory(getGsonConverterFactory())
        .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
        .baseUrl("http://www.demo.com/")
        .client(client)
        .build()
  }

Timeout

可以給每套服務設定不同的超時

@BaseUrl("https://www.b.com/")
@Timeout(read = 100,timeUnit = TimeUnit.SECONDS)
interface ApiB {
  @GET("user/loginWithScanCode")
  fun methodB(@Query("id") id: Int): Observable<ResponseBody>
}

到此這篇關於詳解Android專案多服務端介面適配(超簡單)的文章就介紹到這了,更多相關Android多服務端介面適配 內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!