[android]Jetpack(1)-LiveData、ViewModelについて


鄭代理のYouTubeを開発する。で学習した内容

🚀 Jetpackって何?


JetpackはAndroidの公式ドキュメントのライブラリの集合であり、開発者がベストプラクティスに従い、よく使われる古いコードを減らし、Androidバージョンとデバイスで一致して動作するコードを作成し、開発者が興味のあるコードに集中できるようにします.
Jetpackを使う理由はいろいろあります.現代の設計に基づいて、以前のバージョンとの互換性により競合を低減し、メモリの漏洩を低減します.バックグラウンドタスク、ナビゲーション、ライフサイクル管理などの冗長なアクティビティを管理することで、より集中できます.

ViewModel


ViewModelは、従来のライフサイクル駆動の開発方式とは異なり、ライフサイクルの影響を受けないクラスです.メモリクリーンアップは、オフの場合にのみonCleared()で行います.

ViewModelの実装


viewModelを使用するには勾配を設定する必要があります.
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version")

LiveData


LiveDataは、観察可能なデータholderクラスです.一般的な観察とは異なり、ライフサイクルを認識しています.つまり、アクティビティ、計画、サービスなどの他のアプリケーションコンポーネントのライフサイクルを考慮します.ライフサイクル識別により、アクティブなライフサイクル状態にあるアプリケーションコンポーネントのオブザーバーのみが更新されます.すなわち,acive状態であれば常に更新される.
LifecycleOwnerというクラスを持ち、現在のライフサイクルを理解する唯一の方法getLifecycle()です.

なぜLiveDataを書くのですか?


1.UIとデータ状態の一貫性を保証する.
->livedataはobserverモードに従います.したがって、基本データが変更されると、observerオブジェクトに通知されます.このobserverモードは、データ変更が発生したuiを迅速かつ正確に更新し、データ状態とuiが常に一致することを保証します.
2.メモリ漏れはない.
->observerはライフサイクルオブジェクトにマージされ、接続のライフサイクルが終了すると自動的に削除されます(destroy).
3.正常に終了するのではなく、停止した活動によるものはありません.
->アクティブデバイスがバックグラウンドにある場合、またはobserverのライフサイクルが非アクティブな場合、livedataイベントは受信されません.
4.ライフサイクルを手動で処理しない.
->UIコンポーネントは関連データのみを観察し、停止または再起動しません.観察中は、関連するライフサイクル状態の変化を認識し、自動的に管理します.
5.最新データの保持
->ライフサイクルが非アクティブからアクティブに移行すると、最新のデータが受信されます.
6.リソースを共有できます.
->LiveDataを継承し、任意のクラスを個別に実装し、単一トーンモードでアプリケーションのどこでもリソースを共有できます.

LiveDataの実装


LiveDataを使用するには、階層設定が必要です.
implementation("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version")

LiveDataの使用方法


単純な例で加算と減算のみを実行する計算機を作成します.

MyNumberViewModel.kt

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel

// 두 가지 액션타입 생성
enum class ActionType {
    PLUS, MINUS
}

// 데이터의 변경을 가짐
// 뷰모델은 데이터의 변경사항을 알려주는 라이브데이터를 가진다
class MyNumberViewModel : ViewModel() {

    // mutable 라이브 데이터 - 수정가능
    // 라이브 데이터 - 값 변동 안됨

    // 내부에 생성하는 데이터는 mutable로
    // 변경 가능하도록 설정
    private val _currentValue = MutableLiveData<Int>()

    // 변경되지 않는 데이터를 가져 올때 이름을 _ 언더스코어 없이 설정
    // 공개적으로 가져오는 변수는 private이 아닌 퍼블릭으로 외부에서도 접근 가능하도록 설정
    // 하지만 값을 직접 라이브 데이터에 접근하지 않고, 뷰모델을 통해 가져올 수 있도록 설정
    val currentValue: LiveData<Int>
        get() = _currentValue

    // 초기값 설정
    init {
        _currentValue.value = 0
    }
	// 액션타입에 따른 update
    fun updateValue(actionType: ActionType, input: Int) {

        when (actionType) {
            ActionType.PLUS ->
                _currentValue.value = _currentValue.value?.plus(input)
            ActionType.MINUS ->
                _currentValue.value = _currentValue.value?.minus(input)
        }
    }
}

MainActivity.kt

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity(), View.OnClickListener {

    lateinit var myNumberViewModel: MyNumberViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        // viewmodelprovider를 통해 viewmodel을 가져온다
        myNumberViewModel = ViewModelProvider(this).get(MyNumberViewModel::class.java)

        // viewmodel의 livedata에 접근후 observe로 관찰
        myNumberViewModel.currentValue.observe(this, Observer {
        	// 값이 변경되는데로 바로바로 적용
            number_textview.text = it.toString()
        })

        // connect listener
        plus_btn.setOnClickListener(this)
        minus_btn.setOnClickListener(this)
    }

    // 클릭
    override fun onClick(view: View?) {
        val userInput = userinput_edittext.text.toString().toInt()

        when(view) {
            plus_btn ->
                myNumberViewModel.updateValue(actionType = ActionType.PLUS, userInput)
            minus_btn ->
                myNumberViewModel.updateValue(actionType = ActionType.MINUS, userInput)
        }
    }
}