前人未踏の領域へ Androidアプリ開発編

Androidアプリ開発に関する調査メモ置き場。古い記事にはアプリ以外も含まれます。

suspend関数を処理可能なラムダパラメータを定義する

タイトルも本文も何言ってるか分からないかもしれないけれどちょっと感動したので。

課題

ViewModel内の関数で、コルーチン内部でラムダを実行させたい。 このラムダは内部でRetrofitによるsuspend関数のAPI呼び出しを行うためsuspend関数の実行が必要である。どうすればよいか。

対応

ラムダをsuspend関数化したパラメータとして受け取るようにする。

// 共通のレスポンスを返すAPIを扱う関数
fun doQuery(text:String, query: suspend (id:Int) -> Response) {
    viewModelScope.launch {

        // 共通の前処理

        // APIを実行
        val response = query(id)
        
        // 以下、responseを使った共通処理
    }
}

呼び出し側(1)

   doQuery("ほげ") { id ->
         repository.getHogeItems(id)
   }

呼び出し側(2)

   doQuery("ふが") { id ->
         repository.getFugaItems(id)
   }

query: suspend (id:Int) -> Response) がポイント。 ラムダ定義のとこに suspend つけてあげるとそれがsuspend関数になる。 いや〜、Kotlin便利だわ。

Kotlin : 代入とgetterと by lazy

課題

こんなコードがあったとして

// 1 getter
val nickname: String?
    get() = _user.value?.nickname

// 2 代入
val nickname: String? = _user.value?.nickname

// 3 by lazy
val nickname: String? by lazy {
     _user.value?.nickname
}

// 4 関数
fun nickname(): String? = _user.value?.nickname

それぞれ何が違うのかがふと気になったので確認。

回答

  1. 都度処理結果が返される
  2. オブジェクト初期化時に一度だけ呼ばれ、以後変更されない
  3. 最初に参照された時点でブロックの処理結果が代入され、以後変更されない
  4. 都度処理結果が返される

4の記法が頭に残ってたせいで1を2に書き換えたくなったけど
冷静に考えたらそれってただの代入だから挙動違うよね、という話。

Android: BundleにEnumをセットする

課題

画面間の値渡しでBundleにEnumの値をセット、取得したい。どうすればよいか。

対応

EnumはSerializableなので Bundleの putSerializable メソッドが使える。

enum class Mark {
    HEART,
    SPADE,
    DIAMOND,
    CLUB
}


fun newInstance(): CardFragment {
    return CardFragment().apply {
        arguments = Bundle().apply {
            putSerializable("Mark", Mark.SPADE)
        }
    }
}
    override fun onAttach(context: Context) {
        super.onAttach(context)
        val mark:Mark = requireArguments().getSerializable("Mark")!! as Mark
    }

長いことAndroidやってるのに BundleにEnumそのままセットできるの知らんかった...。