본문 바로가기

Android/AAC

[Android] ViewModel 기본 개념

728x90

ViewModel

  • ViewModel이란 Android Jetpack의 구성요소 중 하나.
  • MVVM(Model - View - ViewModel) 디자인 패턴으로부터 파생됨.
  • AAC ViewModel 이라고 부르기도 한다.

ViewModel의 특징

  • 라이프 사이클을 고려하여 UI 관련된 데이터를 저장, 관리하기 위해 설계.
  • 화면 전환과 같이 설정이 변경되는 상황에서도 Data를 유지시킨다.
  • Activity가 끝날 때까지 사라지지 않고, View의 생명주기와 별개로 흘러간다.
  • ViewModel은 Activity 생명주기 외부에 존재하기 때문에 UI 컨텍스트를 ViewModel에 저장한다면 Memory Leak을 발생시키는 원인이 될 수 있다.

ViewModel의 생명주기

https://developer.android.com/topic/libraries/architecture/viewmodel#java

일반적으로 onCreate()를 처음 호출할 때 ViewModel을 요청한다.

onCreate()는 화면이 회전할 때 등 여러 번 호출될 수 있다. 이 때 ViewModel은 여전히 메모리 상에 남아있다.

Activity의 finish() 호출 등에 의해 액티비티 생명주기가 종료됨에 따라, LifecycleEventobserver를 통해 ViewModel도 onCleared() 콜백 메서드를 호출하고 종료된다.

 

ViewModel 구현

// ViewModel Class
    public class MyViewModel extends ViewModel {
        private MutableLiveData<List<User>> users;
        public LiveData<List<User>> getUsers() {
            if (users == null) {
                users = new MutableLiveData<List<User>>();
                loadUsers();
            }
            return users;
        }

        private void loadUsers() {
            // Do an asynchronous operation to fetch users.
            users.add(new User("name", 1);
        }
    }
    

 

ViewModel을 사용하려면 ViewModel 클래스를 상속받아서 사용하며, LiveData에 원하는 데이터를 세팅하여 사용한다.

 

// MainActivity class
    public class MyActivity extends AppCompatActivity {
        public void onCreate(Bundle savedInstanceState) {
            MyViewModel model = new ViewModelProvider(this).get(MyViewModel.class);
            model.getUsers().observe(this, users -> {
                // update UI
                sampleText.setText(user);
            });
        }
    }

ViewModel을 생성하기 위해서는 ViewModelProvider 객체가 필요하다.

ViewModelProvider를 이용하여 ViewModel 객체를 생성하고 LiveData 객체를 받아 UI를 업데이트 하는 방식으로 사용한다.

 

Fragment간의 Data 공유

액티비티 내에서 Fragment간의 데이터, 이벤트 공유는 일반적이다.

이 때, ViewModel을 사용하여 이를 공유하도록 구현한다면, Fragment간의 데이터, 이벤트 공유를 쉽게 처리할 수 있다.

 

    public class SharedViewModel extends ViewModel {
        private final MutableLiveData<Item> selected = new MutableLiveData<Item>();

        public void select(Item item) {
            selected.setValue(item);
        }

        public LiveData<Item> getSelected() {
            return selected;
        }
    }

    public class MasterFragment extends Fragment {
        private SharedViewModel model;

        public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            model = new ViewModelProvider(getActivity()).get(SharedViewModel.class);
            itemSelector.setOnClickListener(item -> {
                model.select(item);
            });
        }
    }

    public class DetailFragment extends Fragment {

        public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            SharedViewModel model = new ViewModelProvider(getActivity()).get(SharedViewModel.class);
            model.getSelected().observe(getViewLifecycleOwner(), { item ->
               // Update the UI.
            });
        }
    }
    

위의 예제는 SharedViewModel에 Master, Detail Fragment 두 개가 동시에 접근하고 있다.

여기서 getActivity()를 사용해서 ViewModeProvider 객체를 얻기 때문에 두 Fragment에서 사용하는 ViewModel은 동일한 인스턴스가 된다.

따라서, Fragment의 생명주기 동안에 ViewModel을 사용하여 자유롭게 데이터를 공유할 수 있게 된다.

 

이와 같이 ViewModel을 공유하여 Fragment가 데이터를 공유하는 방법은 다음과 같은 장점을 갖는다.

  • Activity가 각 Fragment간 데이터 전달 시 추가적인 작업을 하지 않아도 된다. (Activity가 Fragment 커뮤니케이션에 개입하지 않는다)
  • 각 Fragment는 SharedViewModel 외 다른 부분에 의존하지 않아도 된다. 따라서, Fragment 중 하나가 사라지더라도 다른 Fragment는 정상 동작 한다. (Fragment간 의존하지 않는다)
  • Fragment는 각각의 생명주기를 가지고 있다. 따라서, 서로의 생명주기에 영향을 주거나 받지 않는다.

즉, Activity와 Fragment들의 의존성이 낮아지면서 유지보수나 확장성 측면에서 높은 효율을 볼 수 있다.

728x90