Edited at

【Android】Retrofit + Rx


Retrofit

公式ページ

RetrofitのRx化に関しては Jake神作のAdapterを使っていたらしい。。が

現在本家のretrofitにAdapterが出来てるみたいで Jake神作のはDEPRECATEDになっている。

こちらを使う:eyes:


:computer:環境構築


app/build.gradleに以下を追加

    implementation 'io.reactivex.rxjava2:rxjava:2.1.6'

implementation 'io.reactivex.rxjava2:rxkotlin:2.1.0'
implementation 'com.squareup.moshi:moshi:1.5.0'
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0'
implementation 'com.squareup.retrofit2:converter-moshi:2.4.0'


:pencil: 実装



簡単なサンプル

サンプルとしても多い、GithubのAPIを使ってユーザー情報を取得して見ます。



  • Userクラス (ユーザー情報を格納するデータクラス)

    import com.squareup.moshi.Json

    data class User(
    @Json(name = "name")
    var name: String,
    @Json(name = "login")
    var login: String,
    @Json(name = "blog")
    var blog: String,
    @Json(name = "type")
    var type: String
    )




  • GithubApiクラス (interfaceを定義)

    import io.reactivex.Observable
    
    import retrofit2.http.GET
    import retrofit2.http.Path

    interface GithubApi {

    companion object {
    const val BASE_URL = "https://api.github.com"
    }

    @GET("users/{username}")
    fun getUser(@Path("username") user: String): Observable<User>
    }




  • MainActivityクラス

    class MainActivity : AppCompatActivity() {

    companion object {
    val TAG = MainActivity::class.java.simpleName
    }
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val retrofit = Retrofit.Builder()
    .baseUrl(GithubApi.BASE_URL)
    .addConverterFactory(MoshiConverterFactory.create(Moshi.Builder().build()))
    .addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))
    .build()

    val service = retrofit.create(GithubApi::class.java)
    service.getUser("Slowhand0309").subscribe({ ret ->
    Log.d(TAG, "ret $ret")
    }, { error ->
    Log.e(TAG, error.message)
    })
    }
    }



AndroidManifestに

<uses-permission android:name="android.permission.INTERNET"/> を追加するのを忘れずに


戻り値に関して

RetrofitのRxJava2 Adapterは戻り値として

Observable, Single, Maybe, Completable

を提供している、が、それぞれの違いがわからないので調べてみる。


  • Observable: いつも使っているので省力

  • Single


    • onNext+onComplete = onSuccess でonSuccessは一回しか呼べない



  • Maybe


    • onSuccessかonErrorかonCompleteのどれかが呼ばれる、または全く呼ばれません。



  • Completable


    • onErrorかonCompleteのどれかが呼ばれる、または全く呼ばれません。



参考URL



エラー処理に関して

200番台以外のレスポンスの場合 HttpException として onError が呼ばれる

実際のソースコード

エラー処理に関しては↓のように捌けば良さそう。

        disposable += ApiClient.createUser()

.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ res ->
Log.d(TAG, "create user success ${res.id}")
}, { error ->
(error as? HttpException)?.let {
Log.e(TAG, "code: ${it.code()}")
Log.e(TAG, "message: ${it.message()}")
Log.e(TAG, "response: ${it.response()}")
}
})

401が返ってきた場合の実際の出力

E/MainActivity: code: 401

message:
E/MainActivity: response: Response{protocol=h2, code=401, message=, url=https://....}


:bomb: バッドノウハウ


単純にmoshiを使うだけだと、dataクラスのnon-nullのプロパティにnullが入ってしまう!

参考URL

そこでmoshiのkotlin extensionを導入して、non-nullにnullを入れうようとしたら

例外を投げるように修正

app/build.gradleに以下を追加

implementation 'com.squareup.moshi:moshi-kotlin:1.5.0'

MainActivityのmoshiを生成している箇所をいかに変更

        val moshi = Moshi.Builder()

.add(KotlinJsonAdapterFactory())
.build()

val retrofit = Retrofit.Builder()
.baseUrl(GithubApi.BASE_URL)
.addConverterFactory(MoshiConverterFactory.create(moshi))
.addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))
.build()

これでnon-null / null をきっちり管理してくれます:thumbsup:


:link: 関連リンク