코코딩딩

[안드로이드] ViewModel , LiveData 본문

코딩/Android

[안드로이드] ViewModel , LiveData

겟츄 2022. 4. 5. 22:36

ViewModel은 화면회전과 같은 동작을 할 때 수명주기에 의해 activity가 처음부터 다시 시작해도 데이터를 유지할 수 있게 해준다. 그리고 UI와 비즈니스로직을 분리해 코드를 작성 할 수 있어 프로그램을 유지보수 하는데도 도움을 준다.

이는 MVVM 패턴과 연관이 있는데 깊게 알고 싶긴 하지만 당장 동작하는 코드를 보면서 안드로이드에 대한 기본 이해를 높이고자 코드 중심으로 살펴보려고 한다.

 

https://www.youtube.com/watch?v=Y-uPcwBEEV4 영상을 참고해서 예제를 제작하였다.

 


1. gradle dependencies 추가

 

implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'

android 개발자 문서에 있는 implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.4.1'와 같은 것들도 있지만 참고한 코드가 위의 종속성을 사용하고 있어 일단 이것을 쓸 것이다.

 

2. ViewModel.class 만들기

 

public class MainActivityViewModel extends ViewModel {
    public MutableLiveData<Integer> counter = new MutableLiveData<>();

    public MainActivityViewModel(){
        counter.setValue(0);
    }

    public void increase(){
        counter.setValue(counter.getValue() + 1);
    }
    public void decrease(){
        counter.setValue(counter.getValue() - 1);
    }
}

 

ViewModel을 만드는 방법은 간단하다. 어떤 클래스의 ViewModel인지 구분할 수 있게 이름을 정해주고 ViewModel을 상속하면 된다. 위의 코드는 Livedata인 counter를 선언해주고 counter 값을 1씩 증감 시키는 메서드를 만들어주었다.

.setValue를 이용해 livedata의 값을 초기화 해 준다. 

 

 3. MainActivity

 

public class MainActivity extends AppCompatActivity {

    private ActivityMainBinding binding;
    private MainActivityViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewModel = new ViewModelProvider(this).get(MainActivityViewModel.class);
        binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
        binding.setLifecycleOwner(this);

        binding.setViewModel(viewModel);
		
        // 이 아래는 한 프로젝트에 여러개를 추가하기 위해 넣은 것으로 예제와 상관없다.
        binding.btnMove.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(getApplicationContext(),VmShareActivity.class);
                startActivity(intent);
            }
        });
    }
}

 

이전에 했던 databinding이 적용되어 있는 상태이고 MainActivityViewModel viewModel 을 선언해주고

viewModel을 new로 생성해준다. 영상에서는 viewModelProviders 를 사용하는데 이는 deprecated 되었기 때문에

위에적힌 방법을 사용해준다.

 

// 이런 코드는 ViewModel과 databinding을 이용해 생략할 수 있다.
binding.btnPlus.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        viewModel.increase();
    }
});

 

나머지 코드들을 보면 위와 같은 click 이벤트에 대한 내용이 없는 것을 알 수 있는데 지금부터 databinding을 이용해

viewmodel을 조금 더 깔끔하게 사용하는 방법을 사용하려고 한다.

 

3. viewmodel + databinding ( MainActivity.xml )

 

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    
    <data>
        <variable
            name="viewModel"
            type="com.example.counterre.MainActivityViewModel" />
    </data>
    
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:id="@+id/tv_count"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="24sp"
            android:text="@{Integer.toString(viewModel.counter)}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <com.google.android.material.floatingactionbutton.FloatingActionButton
            android:id="@+id/btn_plus"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:clickable="true"
            android:onClick="@{()-> viewModel.increase()}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:srcCompat="@drawable/plus" />

        <com.google.android.material.floatingactionbutton.FloatingActionButton
            android:id="@+id/btn_minus"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:clickable="true"
            android:onClick="@{()-> viewModel.decrease()}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:srcCompat="@drawable/minus" />

        <Button
            android:id="@+id/btn_move"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="8dp"
            android:text="이동"
            android:textSize="24sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

 

위의 코드 처럼 <data>를 추가해 주면 xml에서 ViewModel 에 있는 코드들을 사용할 수 있다.

textView에 있는 값은 android:text="@{Integer.toString(viewModel.counter)}"에 의해 ViewModel에 있는 counter의 값이 변할 때 마다 세팅된다. Integer.toString을 해준 이유는 textView이기 때문이다.

 

button에 클릭 이벤트를 세팅하기 위해서는 android:onClick="@{()-> viewModel.increase()}" 이와같은 코드를 추가해준다.

 

4. 동작화면

 

동작 순서를 나열해 보자면 ViewModel에 있는 livedata인 counter를 textview에 세팅해주고 버튼을 누르면 increase 메서드가 실행되고 counter의 값이 변경되면 mainactivity에 있는 binding.setLifecycleOwner(this); 에 의해서 실시간으로 값이 변경된 것을 확인해준다.

 

 

 

'코딩 > Android' 카테고리의 다른 글

[안드로이드] DataBinding  (0) 2022.03.31
[안드로이드]Dialog 만들기 (DialogFragment, Custom Dialog)  (0) 2022.03.30