今はまだ必要な Android ライブラリ の Bill of Materials(BOM) のURLs

以下は、Androidアプリ開発には、必ず使いますよね。

いや使うと良い、か。

 

Kotlin Libraries Bill of Materials

👉 Maven Repository: org.jetbrains.kotlin » kotlin-bom 

 

Kotlinx Coroutines BOM

👉 Maven Repository: org.jetbrains.kotlinx » kotlinx-coroutines-bom 

 

firebase-bom

👉 Google's Maven Repository - BOM 

 

OkHttp BOM

👉 Maven Repository: com.squareup.okhttp3 » okhttp-bom 

latest の更新に注意するためのな。

👉 bom - Google's Maven Repository 
👉 org.jetbrains - Maven Central Repository Search 


Paging3 ライブラリ

👉 Paging 3 library overview  |  Android デベロッパー  |  Android Developers 

「ページングライブラリ」は、ローカルストレージやネットワーク経由のより大きなデータセットを読み込みページを表示する処理に使います。これを使うことで、ネットワーク帯域幅とシステムのリソースを効果的に使うことができます。Android app architecture にフィットするように設計されており、他の JetPack コンポーネントとも綺麗に統合することができます。

メリット

ページングライブラリには以下の機能があります。

- ページ分けされたデータのメモリーキャッシュ化。システムリソースを効果的に使います、
- 重複リクエストの排除。ネットワーク帯域とシステムリソースを効果的に使います。
- 設定可能な指導リクエスト付き RecyclerView Adapter。ロード済みデータとスクロールを考慮。
- Kotlin coroutine と Flow を最優先。LiveData や RxJava のように利用可能。
- リフレッシュやリトライを含んだエラーハンドリング。

👉 componentid:413106 status:open - Issue Tracker 

設定

build.gradle に以下のようにして dependencies に追加します。


dependencies {
  def paging_version = "3.0.0-alpha01"

  implementation "androidx.paging:paging-runtime:$paging_version"

  // alternatively - without Android dependencies for tests
  testImplementation "androidx.paging:paging-common:$paging_version"

  // optional - RxJava2 support
  implementation "androidx.paging:paging-rxjava2:$paging_version"

  // optional - Guava ListenableFuture support
  implementation "androidx.paging:paging-guava:$paging_version"
}

構成

Paging ライブラリは、推奨されている Android app architecture に直接統合できます。ライブラリコンポーネンツはアプリの中で3つのレイヤーを持っています。

- Repository レイヤー
- ViewModel レイヤー
- UI レイヤー

ここでは、Pagingライブラリコンポーネントがそれぞれのレイヤーでどのように組み合わせてく使われ、データ読み込みからページを表示するまでを説明します。

Repository レイヤー

Repository レイヤーで、主要な Pagingライブラリコンポーネントとなるのが PagingSource です。それぞれの PagingSource オブジェクトはデータソースとそれをどう走査するかを定義します。PagingSource オブジェクトは、ネットワークやローカルデータベースなど一つのソースからデータをロードします。

もうひとつは、RemoteMediator です。 これは、ネットワークデータソースとローカルデータキャッシュのようなレイヤー分けされたデータからのページングを管理します。

ViewModel レイヤー

Pager コンポーネントは、PagingSource や PagingConfig オブジェクトから PagingData インスタンスを作成するためのパブリックなAPIを提供します。

ViewModelレイヤーとUIを接続するコンポーネントは、PagingData です。PagingData オブジェクトは、ページ付けされたスナップショットのコンテナです。PagingSourceオブジェクトに問い合わせし、その結果を保持します。

UI レイヤー

UIレイヤーで主要ページングライブラリコンポーネントは、PagingDataAdapterです。RecyclerView のアダプターでページ付けされたデータを取り扱います。

代替として、 独自のカスタムアダプターを作るのに AsyncPagingDataDiffer コンポーネントを使うこともできます。

その他

ページングライブラリについてもっと学ぶために、以下のリソースも参照してください。

👉 Android Paging 
👉 architecture-components-samples/PagingSample at paging3 · android/architecture-components-samples 
👉 architecture-components-samples/PagingWithNetworkSample at paging3 · android/architecture-components-samples 


Retorofit + JSON には「Kotlin Serialization Converter」がよい。

Retrofit は非常に有名なSquare製のJavaで書かれたAndroid 向け HTTP クライアントです。

👉 square/retrofit: Type-safe HTTP client for Android and Java by Square, Inc. 

その内部には Kotlin Serialization はサポートされていませんが、オブジェクトのシリアル化のためのコンバータファクトリを追加することができます。独自のコンバータファクトリを作成することもできますし、Jake Wharton が書いたものを使うこともできます。

👉 JakeWharton/retrofit2-kotlinx-serialization-converter: A Retrofit 2 Converter.Factory for Kotlin serialization. 

Retrofit2 Converter.Factory を利用するには、ライブラリ dependencies に追加したあと、Retorofit インスタンス生成時に、Extension Function である asConvertFactory を使ってそれを追加します。


val contentType = "application/json".toMediaType()

val retrofit = Retrofit.Builder()
 .baseUrl("https://www.example.com")
 .addConverterFactory(Json.asConverterFactory(contentType))
 .build()

簡単ですね!

ちなみに、.toMediaType() とは、


okhttp3.MediaType.Companion.toMediaType

です。

👉 「Kotlinx Json」の登場でサードパーティJSONライブラリは不要となる。 


「Kotlinx Json」の登場でサードパーティJSONライブラリは不要となる。

JSONのライブラリ何を使ってますか?

👉 square/moshi: A modern JSON library for Kotlin and Java. 
👉 FasterXML/jackson: Main Portal page for the Jackson project 
👉 google/gson: A Java serialization/deserialization library to convert Java Objects into JSON and back 

これらは、Javaベースで書かれています。Kotlin は100%相互運用可能ですが微妙に期待しない挙動をします。


data class User(
    val name: String,
    val email: String,
    val age: Int = 13,
    val role: Role = Role.Viewer
)

enum class Role { Viewer, Editor, Owner }


{
    "name" : "John Doe",
    "email" : "[email protected]"
}


class JsonUnitTest {

    private val jsonString = """
            {
                "name" : "John Doe",
                "email" : "[email protected]"
            }
        """.trimIndent()

    @Test
    fun gsonTest() {
        val user = Gson().fromJson(jsonString, User::class.java)

        assertEquals("John Doe",user.name)
        assertEquals(null, user.role)
        assertEquals(0, user.age)

//      User(name=John Doe, 
//           [email protected], 
//           age=0, 
//           role=null)

    }

}

デフォルト値が期待通りにパースできません。

kotlinx.serialization が登場!!

JetBrains産です。間違いないでしょう。



👉 Kotlin/kotlinx.serialization: Kotlin multiplatform / multi-format serialization 

- クロスプラットフォーム
- 非リフレクション
- アノテーション @Serializable
- Kotlin v1.3.30+


@Serializable
data class User(
    val name: String,
    val email: String,
    val age: Int = 13,
    val role: Role = Role.Viewer
)

enum class Role { Viewer, Editor, Owner }

class JsonUnitTest {

    private val jsonString = """
            {
                "name" : "John Doe",
                "email" : "[email protected]"
            }
        """.trimIndent()

    @Test
    fun jsonTest() {
        val user = Json.parse(User.serializer(), jsonString)

        assertEquals("John Doe", user.name)
        assertEquals(Role.Viewer, user.role)
        assertEquals(13, user.age)

//      User(name=John Doe, 
//           [email protected], 
//           age=13, 
//           role=Viewer)

    }
}

Gson では無視されていたデフォルト値がきちんと使用されます。

以下のセットアップでどうぞ。


buildscript {
    ext.kotlin_version = '1.3.60'
    repositories { jcenter() }

    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
    }
}


apply plugin: 'kotlin' 
apply plugin: 'kotlinx-serialization'


repositories {
    jcenter()
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.14.0" // JVM dependency
}

👉 Kotlinx Json vs Gson - Juraj Kušnier - Medium 



今どきの Retrofit と LiveData で Coroutine

ありがとうございます。


👉 Retrofit 

ご存知の通り Retrofit2 では、サスペンドな関数も利用できるようになっております。

👉 SpaceX REST API で試す Retrofit の coroutine 対応 


// NewModel.kt
@GET("/feed/here/")
suspend fun getData(@Query("token") token : String) : Status


// NewRepository.kt
class Repository {
  var client = RetrofitService.createService(JsonApi::class.java)
  suspend fun getData(token : String) = client.getData(token)
}

ので、以下のようなこれまでのコードは、


// OldViewModel.kt
val data = MutableLiveData<Status>()

private fun loadData(token: String){
  viewModelScope.launch {
    val retrievedData = withContext(Dispatchers.IO) {
      repository.getData(token)
    }
    data.value = retrievedData
  }
}

シンプルに以下のように書けます。


// NewViewModel.kt
val data : LiveData<Status> = liveData(Dispatchers.IO) {
      val retrievedData = repository.getData(token)
      emit(retrievedData)
    }

ありがとうございます。

👉 Exploring new Coroutines and Lifecycle Architectural Components integration on Android 
👉 Using Retrofit 2 with Kotlin coroutines - ProAndroidDev