본문 바로가기
2023년 이전/Android

Android -LiveData

by JeongUPark 2019. 10. 15.
반응형

Android Developer에서 설명하는 LiveData란 관찰기능한(Observable) 데이터 홀더 클래스입니다. 간단히 설명하면 Activity나 Fragment, service의 life cycle을 따르는데, LiveData는 현재 활성화된 생명주기에 있는 앱 컴포넌트 옵저버만 업데이트하도록 보장합니다.

즉, life cycle이 STARTED이거나 RESUMED 일 때, 옵저버가 활성상태 인것으로 간주, 이 활성화 중인 옵저버들에게만 LiveData 업데이트에 대한 알림을 줍니다. (비활성화 상태 STARTED이거나 RESUMED가 아닌 상태는 알림을 받지 않습니다.)

그리고 DESTROYED일 때는 옵저버가 삭제 될 수 있도록 할 수 있기 때문에 메모리 릭에 대한 우려도 없습니다.

 

이런 LiveData의 장점은 다음과 같습니다.

1. UI를 데이터 상태와 일치시킬 수 있다.

2 메모리 릭의 요소를 없앨 수 있다.

3. 정지된 엑티비티들 때문에 Crash날 일이 없다.

4. 직접 생명주기를 핸들링할 필요가 없다

5. 항상 최신 데이터를 유지한다.

6. 구성(Configuration)이 변경되었을 대 적절하게 대응한다.

7. 자원공유

 

그럼 간단한 사용 예제를 보겠습니다.

Android Studio에서

File->Project -> New Project를 선택하시고 Fragment+ViewModel을 선택합니다.

그럼 자동으로 Activity, Fragment, ViewModel이 생성 됩니다.

그 후 생성된 MainViewModel을 다음과 같이 coding 합니다.

class MainViewModel : ViewModel() {
    private val text = MutableLiveData<String>()

    val post: LiveData<String>
        get() = text

    fun changeData(str : String){
        if(post.value.isNullOrEmpty()){
            text.postValue(str)
        }else{
            text.value = str
        }
    }
}

 그리고  Fragment와 xml을 다음과 같이 coding 합니다.

class MainFragment : Fragment() {

    companion object {
        fun newInstance() = MainFragment()
    }

    private lateinit var viewModel: MainViewModel

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        return inflater.inflate(R.layout.main_fragment, container, false)
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)

        viewModel.post.observe(activity!!, Observer {
            for( t  in it){
                Log.d("TEST", "t: $t")
            }
            message.text = it.toString()
        })
        btn_input.setOnClickListener {
            val str = et_input.text.toString()
            if(str == null || str.isEmpty()){
                return@setOnClickListener
            }
            viewModel.changeData(str)
        }
    }
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.main.MainFragment">
    <EditText
        android:id="@+id/et_input"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        app:layout_constraintTop_toTopOf="parent"/>
    <Button
        android:id="@+id/btn_input"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="입력"
        app:layout_constraintTop_toBottomOf="@+id/et_input"/>

    <TextView
        android:id="@+id/message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="MainFragment"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

이렇게 하고 실행하면 

이런 결과가 나오는데 위의 EditText에 문자를 입력하고 입력 버튼을 누르면 가운데 MainFragment라고 적힌 부분이 변경 됩니다.

 

Fragment의 Code를 보면 버튼 클릭시 (btn_input.setOnClickListener) viewModel의 changeData  Method를 호출 하고 changeData Method는 LiveData를 변경합니다.

LiveData가 변경이 되면 Fragment에 있는 viewModel.post.observe(activity!!, Observer { ... })에 Observer가 동작하고 그 안에서 text를 변경합니다.

 

또한, LiveData를 확장자로 사용할 수 도 있습니다.

class ExtendLiveData : LiveData<String>() {

    override fun onActive() {
        super.onActive()
    }

    override fun onInactive() {
        super.onInactive()
    }

    fun onChangeData(str : String){
        value = str
    }

    override fun setValue(value: String?) {
        Log.d("TEST", "setValue value: $value")
        super.setValue(value)

    }

}

이렇게 LiveData를 확장자로 가지는 class를 만들고 적용하면

class MainFragment : Fragment() {

    companion object {
        fun newInstance() = MainFragment()
    }

    private lateinit var viewModel: MainViewModel

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        return inflater.inflate(R.layout.main_fragment, container, false)
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        val mExtendLiveData = ExtendLiveData()
        mExtendLiveData.observe(activity!!, Observer {
            message.text = it.toString()
        })

        btn_input.setOnClickListener {
            val str = et_input.text.toString()
            if(str == null || str.isEmpty()){
                return@setOnClickListener
            }
            mExtendLiveData.onChangeData(str)
        }
    }
}

위의 결과와 동일한 결과를 확인 할 수 있습니다.

 

더 자세한 내용은 Android Developer LiveData 페이지에서 확인하실 수 있습니다.

반응형