AAC-LiveData

8140 단어 androidAACLiveDataAAC

들어가기전에

LiveData같은 경우 회사에서 프로젝트를 하면서 가끔 활용할 때가 있었는데 사용법 정도랑 간단한 개념만 알고 있는 상태였다.
활용하면서 참 편리한 라이브러리라고 생각했는데 이번기회에 좀 더 자세하게 알아보려한다.🏃🏻

LiveData란?

Observer패턴을 사용한 관찰이 가능한 데이터 홀더 클래스이다.
또한 위에서 말한대로 Lifecycle을 활용했기 때문에 LifecycleOwner가 활성 상태일 때만 데이터의 변화를 감지해서 알려준다.

사용했을 때 좋은 점

구글 문서에서는 이렇게 이야기한다.

  1. 데이터가 변경될 때마다 알려주기 때문에 Observer에 UI업데이트 부분이 들어가 있다면 UI와 데이터의 일치가 보장된다.

  2. 생명주기를 알고 있기 때문에 메모리의 누수가 없다.

  3. 관찰하는 주체가 비활성화 상태일 때 데이터 변경에 대한 이벤트를 받지 않으므로 비정상 종료(App Crash)가 나지 않는다.

  4. 수명주기가 비활성화 상태에서 활성 상태로 되돌아 오면 최신 데이터를 받아오기 때문에 최신 데이터를 유지할 수 있다.

  5. 기기 회전과 같은 구성변경이 일어나면 사용가능한 데이터를 바로 불러올 수 있다.

  6. 확장을 지원한다. -> Google 문서

사용

MutableLiveData

LiveData는 추상 클래스이기 때문에 객체를 직접 생성할 수 없다.
또한 LiveData 클래스내에 있는 데이터를 변경해주는 setValue()와 postValue()는 protected로 되어있어 LiveData를 구현한 클래스를 제외한 나머지에서는 쓸 수 없다. 즉 데이터를 변경할 수 없다는 것이다.

MutableLiveData는 LiveData를 구현한 클래스이므로 setValue()와 postValue()를 쓸 수 있다.

왜 그럴까?
보통 LiveData는 ViewModel 내부에 생성된다. ViewModel에서의 관점으로 바라볼때 외부(View)에서 데이터의 변경이 이루어지면 안된다. 그렇기 때문에 데이터의 변경이 가능한 MutableLiveData를 사용함으로써 데이터를 변경하고 LiveData는 외부에서 관찰만 제공하도록 하는 것이다.

하여 사용 시에

//MutableLiveData와 LiveData를 생성하여 두개를 연동하기
class TestViewModel: ViewModel() {

    private val _nameLiveData: MutableLiveData<String> by lazy {
        MutableLiveData()
    }

    val nameLiveData: LiveData<String> = _nameLiveData
}
//MutableLiveData를 LiveData로 변경하여 넘기기
class TestViewModel: ViewModel() {

    private val _nameLiveData: MutableLiveData<String> by lazy {
        MutableLiveData()
    }

    fun name(): LiveData<String> = _nameLiveData
}

변수를 2개를 생성하여 호출할 때의 비용을 줄여주던가 변수를 줄이고 호출할 때의 비용을 늘리는 등의 방식들이 있다.

물론 View 등 외부에서 데이터가 변경되어야하는 상황에서는 적절하게 MutableLiveData를 사용하는 등 상황에 맞게 적절하게 쓰이는 것이 중요하다.

관찰하기

class LiveDataActivity : AppCompatActivity() {

    val viewModel:TestViewModel by viewModels()

    lateinit var binding: ActivityLiveDataBinding // ViewBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityLiveDataBinding.inflate(layoutInflater)
        setContentView(binding.root)


        viewModel.getNameLiveData().observe(this) { name -> //TestViewModel에 있는 LiveData를 가져와 관찰한다.
            //UI update
        }


//        viewModel.nameLiveData.setValue() -> LiveData 객체 이기 때문에 setValue(), postValue()를 쓸 수 없다.
    }
}

위와 같이 observe() 메소드를 사용해 LiveData를 관찰할 수 있다.

특징

MainThread에서 작동

LiveData는 항상 MainThread로 처리된다는 특징이 있다.
따라서 UI를 업데이트 하지 않는 경우라면 LiveData를 사용하지 않는 것이 좋다.

LiveData에서 데이터를 최신화 시켜주는 setValue() 메서드와 postValue() 메서드를 살펴보면 결국은 MainThread에서 동작하게끔 설정이 되어 있다.

두 메서드의 차이라면

  • setValue() : MainThread에서 작동한다. MainThread가 아닌 곳에서 사용 시 런타임에서 오류가 발생한다.
  • postValue() : MainThread가 아닌 다른 Thread에서 작업 시 사용한다. LiveData 내부에서 새로운 값을 가지고 있다가 마지막에 결국 setValue() 를 호출 한다.

postValue()의 경우 코드 중간에 동기화 블록이 있기 때문에 여러 스레드에서 한꺼번에 값을 업데이트 하는 경우 데이터 누락이 발생할 수 있다.

두 메서드 모두 결국 MainThread에서의 작동을 보장한다.
그렇기 때문에 UI 관련 작업을 할 때만 사용하는 것이 올바르다.

활성화

LiveData는 LifecycleOwner 즉 관찰자가 활성화 상태일 때만 데이터의 업데이트를 알린다.

활성화 상태를 판단하는 기준은 관찰자의 수명주기 상태가 STARTED 또는 RESUMED 상태일 경우이다.

그렇기 때문에 활성화 상태가 아닌 관찰자들의 경우 값의 변경이 일어나도 받지 못한다.

관찰자가 STARTED 상태로 진입하게 되면 관찰하고 있던 LiveData에서 최신 값을 받아올 수 있다.

마치며

가끔 회사 프로젝트에서 유용하게 사용했던 LiveData에 대해서 사용법만 알고있었지만 이번 기회에 좀 더 자세하게 알 수 있어서 좋은 포스팅인 것 같다.
LiveData는 내가 정리한 것 이외에 확장, Transformation 클래스를 통한 변환 등 다양한 기능 또한 제공한다.
이 부분들은 필요하게 됬을 때 다시 정리해보는 것이 좋을 것 같다.

좋은 웹페이지 즐겨찾기