Help us understand the problem. What is going on with this article?

KotlinのSealed Classを学ぶ

いつも何となくSealed Classを使っているので、ちゃんと調べて学習した。
学習すると新たな発見もあるし、知識も深まった。

作成したコードはgithubで公開している。
https://github.com/ikemura23/Android-Kotlin-Lab/tree/sealed_class

Sealed Class 公式ドキュメント

まず読むべし

Sealed Classes - Kotlin Programming Language

Sealedという単語の意味

単語の意味が分からないので調べた

sealedの意味・使い方|英辞郎 on the WEB:アルク

  • 密封された
  • 封印された
  • 知られていない
  • 知ることができない

という意味だった

密封されたクラス、って感じになるんだろうか
whenとシールドクラスを組み合わせると便利

Sealedを使うと何が便利か?

  • 状態管理を簡単に表せる
  • 状態に値をもたせられる(Enumではできない)
  • When式で分岐するとき、すべてのケースをカバーしてくれる (ReturnでSealed Classを返す場合のみ)

実際の使い方

画面の状態を表すScreenStateをSealed Classで作った

Sealed Class中身

/**  
 * 画面の状態
 */
 sealed class ScreenState {  
    // エラー  
  object Error : ScreenState()  

    // 読み込み中  
  object Loading : ScreenState()  

    // データ取得完了  
  data class Data(val someData: SomeData) : ScreenState()  
}  

ViewModelでの使い方

MutableLiveDataでSealed ClassのScreenStateを保持する。

class MainViewModel : ViewModel() {
    // Sealed Classの状態
    var state = MutableLiveData<ScreenState>()
    // コルーチンのジョブ
    var job = Job()

    // データ読み込み
    fun load() {
        state.value = ScreenState.Loading // ローディング表示
        job = GlobalScope.launch(Dispatchers.Main) {
            try {
                delay(2000L) // 2秒待つ
                // API通信処理
                val response = SomeData(1) // APIレスポンスを仮作成
                state.value = ScreenState.Data(response) // APIレスポンスを表示
            } catch (e: Exception) {
                state.value = ScreenState.Error // エラー
            }
        }
    }
}

処理によってstateに状態をセットする

Fragmentでの表示の仕方

FragmentではMainViewModelのstateを監視して、状態変化を検知する。
検知したら、when (state)で分岐し、それぞれの状態によって表示を切り替える。

// 変更を検知
viewModel.state.observe(this, Observer<ScreenState> { state ->  
  when (state) {  
        is ScreenState.Loading -> {  
            //ローディング処理  
  Log.d("MainFragment", "Loading")  
        }  
        is ScreenState.Data -> {  
            //データ取得  
  Log.d("MainFragment", state.someData.toString())  
            text.text = state.someData.id.toString()  
        }  
        is ScreenState.Error -> {  
            //エラー処理  
  Log.d("MainFragment", "Error")  
        }  
    }  
})

例えば、この例

sealed class Expr {  
    class Num(val value: Int) : Expr()  
    class Sum(val left: Expr, val right: Expr) : Expr()  
}

全コード

https://github.com/ikemura23/Android-Kotlin-Lab/tree/sealed_class

When式で分岐するとき、すべてのケースをカバーしてくれる

ReturnでSealed Classを返す場合のみ、Whenの分岐漏れをコンパイラが検知して教えてくれる。

Sealed Class

Exprクラスは値を返すNumクラスと値を合計して返すSumクラスを持っている。

sealed class Expr {  
    class Num(val value: Int) : Expr()  
    class Sum(val left: Expr, val right: Expr) : Expr()  
    class Sum2(val left: Expr, val right: Expr) : Expr()  // <= このクラスが追加された時
}  

SumクラスをコピーしてSum2クラスを生成する。

When式

Sum2クラスがwhenの分岐に含まれていない場合、コンパイルエラーとなる。

fun eval(e: Expr): Int =  
    when (e) {  // <= ここでコンパイルErrorになる
        is Expr.Num -> e.value  
  is Expr.Sum -> eval(e.left) + eval(e.right)  
    }

when箇所のエラーメッセージ

Error:(16, 5) Kotlin: 'when' expression must be exhaustive, add necessary 'is Sum2' branch or 'else' branch instead

参考リンク

Sealed Classes - Kotlin Programming Language https://kotlinlang.org/docs/reference/sealed-classes.html

Kotlin Sealed Classes — enums with swag – ProAndroidDev https://proandroiddev.com/kotlin-sealed-classes-enums-with-swag-d3c4b799bcd4

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away