res を複数作って機能・画面別にディレクトリ分けすると分かりやすい

👉 Split layouts into subfolders in Android Studio - ProAndroidDev 

以下のコードを見ながら。

👉 GitHub - android/architecture-samples at dagger-android 

コードは、画面別にディレクトリ分けしてるが、レイアウトファイルは、複雑なファイル名で res ディレクトリ直下に一緒くたに入ってる。

ここで、build.gradle で設定記述を追加する。


android {
  sourceSets {
    main {
      res.srcDirs = [
          'src/main/res',
          'src/main/res/layouts/tasks',
          'src/main/res/layouts/taskdetail',
          'src/main/res/layouts/addedittask',
          'src/main/res/layouts/statistics',
      ]
    }

こうすることで、レイアウトファイル群を画面別に分けることができる。

Android Studio はデフォルトで、一つのディレクトリのみ


android {
  sourceSets {
    main {
      res.srcDirs = [
          'src/main/res'
      ]

と等価な設定を持ってるので、それに、画面別ディレクトリを複数追加することで、Android Studio は、リソースファイルとして複数ディレクトリからファイルを読み込むことができるようになります。

あとは、それぞれのリソースファイルを振り分けて置くだけ。

以下、やってみた動画。



実際は、レイアウトファイルがもっと多くなるはずなので、分かりやすさはより顕著になる。

👉 Split layouts into subfolders in Android Studio - ProAndroidDev 


SQLDelight で View を使うべし

👉 Drive your UI with SQLDelight’s views | Leandro Favarin 
👉 GitHub - cashapp/sqldelight: SQLDelight - Generates typesafe Kotlin APIs from SQL 

SQLDelight は、すべてのクエリーに対して自動的にモデルオブジェクトを作成します。

以下シンプルな名前付きクエリー。


bandsOrderedByName:
SELECT id, name
FROM band
ORDER BY name DESC;

bandsOrderedByAge:
SELECT id, name
FROM band
ORDER BY age;

これから以下が作成される。


data class BandsOrderedByName(id: String, name: String)

data class BandsOrderedByAge(id: String, name: String)

実際は、もっと複雑になります。

以下、join句を使ったクエリーの場合。


SELECT
  band.id,
  band.name,
  album.*
FROM band
JOIN album ON band.id = album.band_id;

SQL View を使うとエレガントになります。


👉 SQLite Query Language: CREATE VIEW 


CREATE VIEW bandWithAlbum AS
SELECT
  band.id,
  band.name,
  album.*
FROM band
JOIN album ON band.id = album.band_id;

bandsOrderedByName:
SELECT *
FROM bandWithAlbum
ORDER BY name DESC;

bandsOrderedByAge:
SELECT *
FROM bandWithAlbum
ORDER BY age;

SQLDelight は、BandWithAlbum タイプを生成します。

続いて、ページネーションの例。


count:
SELECT count(*)
FROM bandWithAlbum;

paged:
SELECT *
FROM bandWithAlbum
LIMIT ?
OFFSET ?;

SQLDelight が生成するモデルは、data クラスなので、DiffUtil コールバックはすぐに書けます。


object BandItemCallback : ItemCallback<BandWithAlbum>() {
  override fun areItemsTheSame(oldItem: BandWithAlbum, newItem: BandWithAlbum): Boolean {
    return oldItem.id == newItem.id
  }

  override fun areContentsTheSame(oldItem: BandWithAlbum, newItem: BandWithAlbum): Boolean {
    return oldItem == newItem
  }
}

また、enum クラスを使ったソートオプション。


enum class Sort { NAME, AGE }

fun bandsSorted(by: Sort): Flow<List<BandWithAlbum>> = when (by) {
  NAME -> db.bandsOrderedByName()
  AGE -> db.bandsOrderedByAge()
}.asFlow().mapToList()

逆に、これらのようなSQL処理をプログラムで実行すると効率は落ちます。
👉 The Resurgence of SQL (Droidcon NYC 2017) - Speaker Deck 

まとめ

欲しいタイプを View にすると、少ないコードで実現できます。

ユーザーの要求は、技術が発達するにつれてますます激しくなることは明らかです。良きユーザエクスペリエンスのための簡単な実装方法を常に把握しておくことが重要になります。


画像読み込みライブラリ「COIL」

Glide や Picasso のような画像読み込みライブラリです。

COroutine
Image
Loader

の略だそうです。

以下の特徴を持っており、ナウい感じです。

- 拡張関数、ラムダなどKotlinの持つ機能を活用。
- コルーチンを利用。
- ディスクキャッシュとストリームバッファリング機能。
- androidx.lifecycle に対応。
- 軽量。
- R8対応。ルール不要。

👉 Introducing Coil: Kotlin-first image loading on Android 

記述例です。


// To load an image into an ImageView, use the load extension function.
imageView.load("https://www.example.com/image.jpg")

// Coil supports urls, uris, resources, drawables, bitmaps, files, and more.
imageView.load(R.drawable.image)

imageView.load(File("/path/to/image.jpg"))

imageView.load(Uri.parse("content://com.android.externalstorage/image.jpg"))

// Requests can be configured with an optional trailing lambda.
imageView.load("https://www.example.com/image.jpg") {
    crossfade(true)
    placeholder(R.drawable.image)
    transformations(CircleCropTransformation())
}

// Custom targets can be created using lambda syntax (onStart and onError are optional).
Coil.load(context, "https://www.example.com/image.jpg") {
    target { drawable ->
        // Handle the successful result.
    }
}

// To get an image imperatively, use the get suspend function.
val drawable = Coil.get("https://www.example.com/image.jpg")

👉 GitHub - coil-kt/coil: Image loading for Android backed by Kotlin Coroutines. 

パフォーマンスを Glide や Picasso と比較した記事がありますが、まあまあのようです。

Coil is a new library, so its performance may increase in the next versions. We are comparing it with mature libraries, so let’s see how it evolves.

Coil は新しいライブラリであるため、次のバージョンでパフォーマンスが向上する可能性があります。成熟したライブラリと比較しているので、どのように進化するか見ておきましょう。

👉 Coil vs Picasso vs Glide: Get Ready… Go! - ProAndroidDev 

ちなみに、必要環境は以下。

- AndroidX
- Min SDK 14+
- Compile SDK: 28+
- Java 8+

今後に期待できますかね。