【Jetpack Compose】ViewModel を捨てて Repository を Composable に直結する

 

気になるのはライフサイクル。

 

きっかけ

フル Compose でよくあるTodoのようなメモのようなアプリを作ってみました。

一通りの機能は実装しました。




👉 Jetpack Compose without ViewModel #shorts - YouTube hatena-bookmark

いろいろ Compose を試しながら進んでいくと ViewModel がスカスカになりました。


@HiltViewModel
class TodoViewModel @Inject constructor(
  private val repository: TodoRepositoryInterface
) : ViewModel() {

  val items: Flow<List<Todo>> = repository.load()

  fun insert(text: String) = repository.insert(text)

  fun update(id: Long, text: String) = repository.update(id, text)

  fun delete(id: Long) = repository.delete(id)

}

ViewModel いらなくね?

ViewModel を省略して、Repository を直結します。

 

結果

以下、少しの書き換えで問題なく動きます。


@Composable
fun TodoScreen(
  //viewModel: TodoViewModel = hiltViewModel()
  repository: TodoRepository = TodoRepository(
    Database(
      AndroidSqliteDriver(
        schema = Database.Schema,
        context = LocalContext.current,
        name = "database.db"
      )
    )
  )
) {


//val items by viewModel.items.collectAsState(initial = emptyList())
val items by repository.load().collectAsState(initial = emptyList())


//viewModel.insert(target.text)
repository.insert(target.text)


//viewModel.update(target.id, target.text) 
repository.update(target.id, target.text)


//viewModel.delete(target.id)
repository.delete(target.id)


//viewModel.delete(target.id)
repository.delete(target.id)

画面回転問題なし、メモリーリークもありません。

すんなりです。

Square製 SQLDelight + Flow(coroutine extension) を使っていますが、

Room + LiveData でもいけると思います。

Composable で Flow(LiveData) を受け取った瞬間に、

collectAsState(ObserveAsState) で State に変換できるんなら、

それのほうが良くね?

ライフサイクルの差も気にしなくていいし。

しかし、緩衝国がなくなるのはなんだか不安です。

Hilt で @Singleton で、ぶち込んでやりたかったです。

あ、でもこれ、 re-compose のたびに、Repository インスタンスが...

(つづく...)

👉 「SwiftUIでMVVMを採用するのは止めよう」と思い至った理由 - Qiita hatena-bookmark
👉 ViewModel はいつ生まれていつ死ぬか 【→ Jetpack Compose】 hatena-bookmark
👉 Jetpack ComposeとViewModelについて考える - Blog - Mori Atsushi hatena-bookmark


【Jetpack Compose】Icon() や Image() で ImageVector をより便利に使う

コード記述のみでベクターのマテリアルアイコン使えます。

drawable の作成が不要なので便利、変更もしやすいです。


Icon(
  imageVector = Icons.Filled.Favorite,
  contentDescription = null
)


Image(
  imageVector = Icons.Filled.Favorite,
  contentDescription = null
)

悪い点としては、

絵柄が49個しかない

絵柄を見ながら選択できない

というところでしょうか。

対応策を考えてみましょう。

 

絵柄が49個しかない

compose 公式のアイコン群(2500個以上)を追加できます。


implementation "androidx.compose.material:material-icons-extended:x.y.z"

エディタのサジェスチョンも大量に増えます。

androidx.compose.material:material-icons-extended

ただ、少し読み込みが遅い。

そこらへんは、公式に注意点があります。

警告: material-icons-extended は大規模なライブラリであり、APK のサイズに影響する可能性があります。そのため、製品版ビルドでは R8/Proguard を使用し、使用されていないリソースを取り除くことを検討してください。また、サイズが大きいために、開発中は、プロジェクトのビルド時間と Android Studio のプレビューの読み込み時間が増加する可能性があります。

👉 Compose のリソース  |  Jetpack Compose  |  Android Developers hatena-bookmark

サイズにも注意する必要があるようです。

 

絵柄を見ながら選択できない

これがすごく困ります。

別で、WEB画面を開くか、Android Studio の Vector Asset Tool を開くかして、絵柄を見て選択して、その名前から、サジェスチョンさせる、くらいしか方法がない。なんかいい方法あったら教えなさいよ。

Material Symbols and Icons - Google Fonts

👉 Material Symbols and Icons - Google Fonts hatena-bookmark

 Vector Asset Tool



将来的には、ライブプレビュー(今現在はリテラルのみ)ですばやく見れるようになるのかもしれません。

Android Studio Electric Eel 以降では、ライブ編集を使用して Compose の開発を高速化できます。ライブ編集は、リテラルのライブ編集をより強力にしたものです。この機能では、プレビューを自動的に更新し、コードの変更をエミュレータまたはデバイスにデプロイすることで、コンポーザブルの更新の影響をリアルタイムで確認できます。

 

👉 Compose のツール  |  Jetpack Compose  |  Android Developers hatena-bookmark

 

まとめ

将来性を見越して、ImageVector を使って


@Composable
fun LikeButton() {
  Button(onClick = {}) {
    Icon(
      imageVector = Icons.Filled.ThumbUp,
      contentDescription = null
    )
    Spacer(Modifier.size(ButtonDefaults.IconSpacing))
    Text("Like")
  }
}

と書きたいです!

Icons.Filled.ThumbUp

ちなみに、これまでのように ベクター drawable を作成して、id で使う記述もできます。


Icon(
  painter = painterResource(id = R.drawable.ic_baseline_favorite_24),
  contentDescription = null
)

しかし、変更時に drawable 消し忘れでゴミが溜まりそう。

あと、

Icons.Default は Icons.Filled のエイリアス

だそうです。

👉 Android Jetpack Compose Icons doesn't contain some of the material icons - Stack Overflow hatena-bookmark

👉 【Jetpack Compose】Compose Settings で数分で設定画面を作る hatena-bookmark


Jetpack Compose Codelabs の日本語ページの説明とGitHub内サンプルコードが違う件

Jetpack Compose Codelabs

👉 Jetpack Compose Codelabs hatena-bookmark

各タイトルのリンクから飛べるドキュメントを見る限り、文章が全く違い、英語ページと日本語ページの最終更新日が数ヶ月違います。

仕様の変化の早い Jetpack Compose ではつらいです。

以下、2022-06-11 現在。

日本語の説明ページの翻訳作業が遅れてるのでしょう。

問題なのは、日本語記事の説明に対して GitHub リポジトリのソースコードが違うことです。

細かく探すとあるのかもしれませんが。

Jetpack Compose Codelabs

Jetpack Compose Codelabs

👉 State in Jetpack Compose hatena-bookmark

Jetpack Compose Codelabs の日本語ページが古い件

👉 tree/end - Jetpack Compose Codelabs hatena-bookmark

あと、説明ページの表示が10秒くらいかかるの何でなんだろ?