ReactiveX 學習筆記(14)使用 RxJava2 + Retrofit2 調用 REST API

JSON : Placeholder

JSON : Placeholder (https://jsonplaceholder.typicode.com/) 是一個用於測試的 REST API 網站。
如下使用 RxJava2 + Retrofit2 調用該網站的 REST API,獲取字符串以及 JSON 數據。java

  • GET /posts/1
  • GET /posts
  • POST /posts
  • PUT /posts/1
  • DELETE /posts/1

全部 GET API 都返回JSON數據,格式(JSON-Schema)以下:react

{
  "type":"object",
  "properties": {
    "userId": {"type" : "integer"},
    "id": {"type" : "integer"},
    "title": {"type" : "string"},
    "body": {"type" : "string"}
  }
}

建立工程

打開 Intellij IDEA,File / New / Project...
在 New Project 嚮導的第1頁,選 Gradle,Project SDK 選 1.8,Additional Libraries and Frameworks 選 Java + Kotlin(Java)。
在嚮導的第2頁填上 ArtifactId
在嚮導的第3頁選中 use auto-import
在嚮導的第4頁點擊 Finish 按鈕建立工程json

build.gradle 內容以下api

plugins {
    id 'java'
    id 'org.jetbrains.kotlin.jvm' version '1.2.60'
}

version '1.0-SNAPSHOT'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
    testCompile group: 'junit', name: 'junit', version: '4.12'
}

compileKotlin {
    kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
    kotlinOptions.jvmTarget = "1.8"
}

將 dependencies 這部分的內容改成:jvm

def retrofit_version = '2.4.0'
dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
    testImplementation group: 'junit', name: 'junit', version: '4.12'
    implementation 'io.reactivex.rxjava2:rxjava:2.1.16'
    implementation 'io.reactivex.rxjava2:rxkotlin:2.2.0'
    implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
    implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofit_version"
    implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
    implementation "com.squareup.retrofit2:converter-scalars:$retrofit_version"
}

這一段一共引用了 RxJava, RxKotlin, Retrofit 3個庫。
其中 Retrofit 這個庫中還包含了 RxJava 的適配器,以及 Gson 和字符串的轉換器。maven

Post 對象

jsonschema2pojo 能夠將 JSON 數據或格式自動轉換爲 Java 的 POJO 類。ide

data class Post(val userId: Int, val id: Int, val title: String, val body: String) {
    override fun toString() =
        "Post {userId = $userId, id = $id, title = \"$title\", body = \"${body.replace("\n", "\\n")}\"}"
}

Post 對象負責 Kotlin 對象與 JSON 數據之間的相互轉換。
因爲二者字段名相同,這裏不須要使用註解。函數

// 若是須要加上註解的話
data class Post(@SerializedName("userId") @Expose val userId: Int,
                @SerializedName("id") @Expose val id: Int,
                @SerializedName("title") @Expose val title: String,
                @SerializedName("body") @Expose val body: String) {
// ...
}

Retrofit 接口

interface RestPost {
    @GET
    fun getPostAsString(@Url url: String): Observable<String>
    @GET("posts/{id}")
    fun getPostAsJson(@Path("id") id: Int): Observable<Post>
    @GET("posts")
    fun getPosts(): Observable<List<Post>>
    @FormUrlEncoded
    @POST("posts")
    fun createPost(@Field("userId") userId: Int,
                   @Field("title") title: String,
                   @Field("body") body: String): Observable<Post>
    @FormUrlEncoded
    @PUT("posts/{id}")
    fun updatePost(@Field("userId") userId: Int,
                   @Path("id") id: Int,
                   @Field("title") title: String,
                   @Field("body") body: String): Observable<Post>
    @DELETE("posts/{id}")
    fun deletePost(@Path("id") id: Int): Observable<String>
}

Retrofit 庫使用專用接口調用 REST API。post

  • 接口中的每個方法都對應於一種 API 調用。
  • 註解 @GET @POST @PUT @DELETE 表示 API 調用時所使用的 HTTP 方法。
  • 註解 @GET 中帶的值表示 API 調用時所包含的相對路徑,其中可包含路徑變量。
    "posts/{id}" 中的 {id} 爲路徑變量。
  • 註解 @Url 表示參數爲路徑。
  • 註解 @Path("id") 表示參數爲路徑變量。
  • 註解 @Field 表示參數爲 HTTP 請求體中的鍵值對。
  • 使用註解 @Field 的方法必須加上註解 @FormUrlEncoded。

Retrofit 對象

val retrofitJson: Retrofit = Retrofit.Builder()
    .baseUrl("https://jsonplaceholder.typicode.com/")
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .addConverterFactory(GsonConverterFactory.create())
    .build()
val retrofitString: Retrofit = Retrofit.Builder()
    .baseUrl("https://jsonplaceholder.typicode.com/")
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .addConverterFactory(ScalarsConverterFactory.create())
    .build()
  • retrofitJson 對象用於處理 REST API 所返回的 JSON 數據。
  • retrofitString 對象用於處理 REST API 所返回的字符串數據。

調用 REST API

fun getPostAsString(): Observable<String> =
    retrofitString.create(RestPost::class.java)
        .getPostAsString("posts/1")

fun getPostAsJson(): Observable<Post> =
    retrofitJson.create(RestPost::class.java)
        .getPostAsJson(1)

fun getPosts(n: Long): Observable<Post> =
    retrofitJson.create(RestPost::class.java)
        .getPosts().flatMapIterable { x -> x }.take(n)

fun createPost(): Observable<Post> =
    retrofitJson.create(RestPost::class.java)
        .createPost(101, "test title", "test body")

fun updatePost(): Observable<Post> =
    retrofitJson.create(RestPost::class.java)
        .updatePost(101, 1, "test title", "test body")

fun deletePost(): Observable<String> =
    retrofitString.create(RestPost::class.java)
        .deletePost(1)
  • getPostAsString 函數取出第1個Post,返回字符串
  • getPostAsJson 函數取出第1個Post,返回Post對象
  • getPosts 函數取出前n個Post,返回n個Post對象
  • createPost 函數建立1個Post,返回所建立的Post對象
  • updatePost 函數更新第1個Post,返回所更新的Post對象
  • deletePost 函數刪除第1個Post,返回字符串

main 函數

fun main(args: Array<String>) {
    getPostAsString().subscribe(::println)
    getPostAsJson().subscribe(::println)
    getPosts(2).subscribe(::println)
    createPost().subscribe(::println)
    updatePost().subscribe(::println)
    deletePost().subscribe(::println)
}

輸出結果

{
  "userId": 1,
  "id": 1,
  "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
  "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}
Post {userId = 1, id = 1, title = "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", body = "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"}
Post {userId = 1, id = 1, title = "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", body = "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"}
Post {userId = 1, id = 2, title = "qui est esse", body = "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"}
Post {userId = 101, id = 101, title = "test title", body = "test body"}
Post {userId = 101, id = 1, title = "test title", body = "test body"}
{}
相關文章
相關標籤/搜索