LoginSignup
4
5

More than 1 year has passed since last update.

Kotlin Flowを使ってみた[Android, Kotlin]

Posted at

やったこと

Firebase Authenticationで作成したアカウントを、ユーザーが削除できる機能を作りました。その際削除が成功したかによってToastを表示したいと思い以下のように実装しました。

1 Repositoryでアカウントを削除
2 ViewModelの isDeleteUser : Flow に削除が成功したかを格納
3 Fragmentで isDeleteUser : Flow の値を収集してToast表示

Repository

Repository.kt
//削除が成功したかどうかを受け取ってViewModelに返します
 suspend fun deleteUser(): Boolean {
        val result = deleteUserFun().getOrThrow()
        if(result) return true
        else {
            Log.e("Error", result.toString())
            return false
        }
    }

//実際のアカウント削除の処理
private suspend fun deleteUserFun(): Result<Boolean> {
        return kotlin.runCatching {
            suspendCoroutine { continuation ->
                user.delete()
                    .addOnSuccessListener {
                        continuation.resume(true)
                    }
                    .addOnFailureListener {
                        continuation.resumeWithException(it)
                    }
            }
        }
    }

ラムダ式を使ってViewModelに値を返すこともできるのですが、コールバック形式は美しくないのでsuspend関数で値を返していきます。
コールバックをsuspend関数でなくす方法についての参考にした記事
https://star-zero.medium.com/callback%E5%BD%A2%E5%BC%8F%E3%81%AE%E3%82%82%E3%81%AE%E3%82%92coroutines%E3%81%AB%E5%AF%BE%E5%BF%9C%E3%81%99%E3%82%8B-9384dfa6ad77

ViewModel

ViewModel.kt
private val _isDeleteUser = MutableSharedFlow<Boolean>()
    val isDeleteUser: Flow<Boolean> = _isDeleteUser

    fun callDeleteUser() {
        viewModelScope.launch(Dispatchers.IO) {
            val result = Repository.repository.deleteUser()
            _isDeleteUser.emit(result)
        }
    }

deleteUser()はsuspend関数で、suspend関数はcoroutineボディ内か他のsuspend関数内からしか呼び出せないのでこのようにしています。resultにdeleteUser()の返り値であるBooleanが格納された後
_isDeleteUser.emit(result)
とすることでMutableSharedFlowに値を送信しています。

また↓このようにしている理由ですが、MutableSharedFlowは再代入が可能なのでFragmentから参照する値をFlowにすることで再代入されることを防いでいます。

private val _isDeleteUser = MutableSharedFlow<Boolean>()
val isDeleteUser: Flow<Boolean> = _isDeleteUser

Fragment

Fragment.kt
viewLifecycleOwner.lifecycleScope.launch {
                viewModel.isDeleteUser.collect {
// itにBooleanが入ってます
                    if (it) Toast.makeText(context, "アカウントを削除しました", Toast.LENGTH_LONG).show()
                    else Toast.makeText(
                        context,
                        "アカウントを削除できませんでした。再度ログイン後削除してください",
                        Toast.LENGTH_LONG
                    ).show()
                }
            }

Flow.collectで値を収集し分岐してToastを表示させています。またcollectもcoroutineかsuspend関数から呼び出す必要があります。

まとめ

emit()で値を送る
collect()で値を収集

最後に

すごく具体的な使い方の解説になりました。Flowについての理解が深まったら凡庸的な使い方についても解説するかもしれません。助言、訂正すべき箇所などあったらどしどしコメントください!!

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5