춤추는 개발자

[AAC] ViewModel을 써야하는 이유? 본문

Android/study_til

[AAC] ViewModel을 써야하는 이유?

Heon_9u 2021. 7. 6. 17:04
728x90
반응형

 이전 포스팅인 LiveData를 써야하는 이유?에서 ViewModel을 언급하였습니다.

ViewModel 클래스는 생명 주기를 고려하여 UI관련 데이터를 저장하고 관리하도록 설계되었습니다. 이러한 ViewModel은 생명 주기를 인식하는 Data Holder 클래스인 LiveData와 함께 사용하고 있습니다.

 

 

✅ViewModel 개요

 Android 프레임워크는 Activity와 Fragment와 같은 UI 컨트롤러의 생명 주기를 관리합니다. 프레임워크는 특정 사용자의 작업이나 완전히 통제할 수 없는 기기 이벤트에 대한 응답으로 UI컨트롤러를 제거하거나 다시 만들도록 결정할 수 있습니다.

 

 만약, 시스템에서 UI컨트롤러를 제거하거나 다시 만드는 경우, 컨트롤러에 저장된 UI관련 일시적인 데이터가 모두 삭제됩니다. 물론 데이터가 단순한 경우, onSaveInstanceState() 메서드를 사용하여 onCreate()의 번들에서 복원될 수 있습니다. 하지만, 이러한 접근 방법은 사용자 목록이나 비트맵과 같은 대용량일 가능성이 높은 데이터가 아니라, 직렬화했다가 다시 역직렬화할 수 있는 소량의 데이터에만 적합합니다.

 

 다른 문제는 UI컨트롤러가 반환하는데 시간이 걸릴 수 있는 비동기 호출을 자주해야 한다는 점입니다. UI컨트롤러는 비동기 호출을 관리하며, 메모리 누수 가능성을 방지해야 합니다. 이러한 관리에는 많은 유지관리가 필요하며, 구성 변경 시, 개체가 다시 생성되는 경우 이미 수행된 메서드를 개체가 다시 호출해야할 수 있으므로 자원이 낭비됩니다.

 

 Activity 및 Fragment와 같은 UI컨트롤러의 목적은 기본적으로 UI데이터 표시. 사용자 작업에 반응, 권한 요청과 같은 운영체제 커뮤니케이션을 처리하는 것입니다.

 이외에도 DB나 네트워크에서 로드를 책임지도록 요구하면 Class가 팽창되며 과도한 책임이 할당됩니다. 이는 결국, 단일 클래스가 앱의 모든 작업을 처리하며 테스트가 어려워질 수 있습니다.

 

 

✅ViewModel 구현

 ViewModel 객체는 구성 요소가 변경되는 동안 자동으로 보관됩니다. 이렇게 보관된 데이터는 다음 Activity 또는 Fragment에서 즉시 사용할 수 있습니다.

 예를 들어, 앱에서 유저들의 목록을 표시해야 한다면 ViewModel 객체에서 유저 목록을 확보하여 Activity나 Fragment 대신 책임을 할당하게 됩니다.

 

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.
    }
}
public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
        // Create a ViewModel the first time the system calls an activity's onCreate() method.
        // Re-created activities receive the same MyViewModel instance created by the first activity.

        MyViewModel model = new ViewModelProvider(this).get(MyViewModel.class);
        model.getUsers().observe(this, users -> {
            // update UI
        });
    }
}

 

 위 코드를 보면 ViewModel에서 getUsers() 메서드로 유저 목록을 책임지고 관리합니다. 대신 Activity에서는 ViewModel의 observe() 메서드를 통해 유저 목록을 가져와 UI에 표시할 수 있습니다.

 그러나 ViewModel 객체는 LiveData 객체와 같이 생명 주기를 인식하는 Observable의 변경사항을 관찰해서는 안됩니다.

 

 

✅ViewModel의 생명 주기

 

 ViewModel 객체의 범위는 ViewModel을 가져올 때, ViewModelProvider에 전달되는 LifeCycle로 지정됩니다. ViewModel은 범위가 지정된 LifeCycle이 영구적으로 경과될 때까지, 즉 Activity에서는 Activity가 끝날 때까지, Fragment에서는 Fragment가 분리될 때까지 메모리에 남아있습니다.

 위 그림에서는 Activity가 화면 회전을 거친 다음 끝날 때까지 다양한 생명 주기 상태를 보여줍니다. 또한, Activity의 동일한 기본 상태는 Fragment의 생명 주기에 적용됩니다.

 

 일반적으로 시스템에서 Activity 객체의 onCreate() 메서드를 처음 호출할 때, ViewModel을 요청합니다. 시스템은 활동 기간 내내 onCreate() 메서드를 여러번 호출할 수 있습니다.(화면 회전)

 

 

 

결국, ViewModel의 주된 역할은 LiveData와 함께 변경된 데이터를 관찰하고, UI 데이터를 관리하는 것입니다. 저도 개인 프로젝트에서 객체들의 추가 및 변경되는 경우 ViewModel을 활용하였습니다. 

 

 

📢추가사항
 이외에도 사용자가 목록에서 항목을 선택하는 Fragment와 선택된 항목의 콘텐츠를 표시하는 또 다른 Fragment가 있는 splie-view Fragment의 경우, ViewModel을 통해 Fragment간 데이터 공유가 가능합니다.
또한, ViewModel로 CursorLoader를 대체하는 경우, Java가 아닌 Kotlin의 코루틴 지원이 포함됩니다.

해당 사항들은 제가 직접 활용했던 부분이 아니라 첨부하지 않았습니다. 만약, 사용할 필요가 생기는 경우 추가적으로 포스팅할 예정입니다.

 

 

 

728x90
반응형