Android

ViewModel (android developers)

 

ViewModel Overview

 

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

 

 


 

ViewModel 클래스는 수명 주기를 고려하여 UI 관련 데이터를 저장하고 관리하도록 설계되었습니다.
ViewModel 클래스를 사용하면 화면 회전과 같이 구성을 변경할 때도 데이터를 유지할 수 있습니다.

 

Android 프레임워크는 activity및 fragment 같은 UI 컨트롤러의 수명 주기를 관리합니다.

시스템에서 UI 컨트롤러를 제거하거나 다시 만들면 컨트롤러에 저장된 일시적인 모든 UI 관련 데이터가 손실됩니다.

예를 들어 앱은 activity 중 하나에 사용자 목록을 포함할 수 있습니다.
화면 회전때문에 activity 가 다시 생성되면 새 activity 는 사용자 목록을 다시 가져와야 합니다.
데이터가 단순한 경우 활동은 onSaveInstanceState() 메서드를 사용하여 onCreate()의 번들에서 데이터를 복원할 수 있습니다.
하지만 이 접근 방법은 사용자 목록이나 비트맵과 같은 대용량일 가능성이 높은 데이터에는 적합하지 않으며,
직렬화했다가 다시 역직렬화할 수 있는 소량의 데이터에만 적합합니다.

또 다른 문제는 UI 컨트롤러가 시간이 좀 걸리는 비동기 호출을 빈번하게 해야한다는 점입니다.
UI 컨트롤러는 이러한 호출를 관리하고 파괴될때 잠재적인 메모리 누수를 피하기 위해서 정리를 해야 하는 많은 유지보수가 필요합니다.
구성 변경으로 객체가 다시 만들어진다면 이미 했던 호출을 다시해야 하기 때문에 자원 낭비가 있을 수 있습니다.

activity 와 fragment 와 같은 UI 컨트롤러는 주로 UI 데이터를 화면에 표시하거나, 사용자 액션에 반응하거나, 퍼미션 요청과 같은 OS 와의 소통을 담당합니다.
UI 컨트롤러가 데이터베이스나 네트워크에서 데이터를 불러오는 일을 한다면 클래스가 비대해지게 됩니다.
UI 컨트롤러에 지나친 책임을 지우는 것은 하나의 클래스가 혼자 앱의 모든 업무를 담당하게 됩니다. 업무를 다른 클래스에 위임하는 대신
이렇게 되면 테스트도 더 힘들어집니다.

뷰 데이터 소유권과 UI 컨트롤러 로직을 분리하는 것이 더 쉽고 효율적입니다.

 

 

Implement a ViewModel

 

아키텍처 구성요소는 UI의 데이터 준비를 담당하는 ViewModel 헬퍼 클래스를 제공합니다.
ViewModel 객체는 구성이 변경되는 동안 자동으로 보관되므로, 이러한 객체가 보유한 데이터는 다음 활동 또는 프래그먼트 인스턴스에서 즉시 사용할 수 있습니다.
예를 들어 앱에서 사용자 목록을 표시해야 한다면 다음 샘플 코드에 설명된 대로 사용자 목록을 확보하여 activity 나 fragment 대신 ViewModel에 보관하도록 책임을 할당해야 합니다.

 

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.
    }
}

 

activity 에서 다음과 같이 목록에 접근할 수 있습니다.

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
        });
    }
}

 

activity 가 다시 생성되면 첫 번째 activity 에서 생성된 동일한 MyViewModel 인스턴스를 받습니다.
소유자 activity 가 종료되면 프레임워크는 리소스를 정리할 수 있도록 ViewModel 객체의 onCleared() 메서드를 호출합니다.

 

 

ViewModel은 view, Lifecycle 또는 activity context 참조를 포함하는 클래스를 참조해서는 안 됩니다.

 

 

ViewModel 이 Application context 가 필요하다면 (시스템 서비스를 찾기 위해서), AndroidViewModel 클래스를 확장할 수 있습니다.
AndroidViewModel 확장하면 생성자에서 Application 을 받습니다. Application 클래스는 Context 를 확장합니다.

 

 

The lifecycle of a ViewModel

 

 

 

ViewModel 객체의 범위는 ViewModel을 가져올 때 ViewModelProvider에 전달되는 Lifecycle로 지정됩니다.
범위가 지정된 Lifecycle (activity, fragment) 이 영구히 사라질 때까지 ViewModel 은 메모리에 남아있습니다.

시스템이 activity 의 onCreate() 메서드를 처음 호출할 때 ViewModel 을 요구합니다.
시스템은 activity 의 생명주기에 여러번 onCreate() 를 호출할 수 있습니다. (화면 회전과 같은 경우)
activity 가 finish 되고 destroy 될 때까지 처음 요구한 ViewModel 은 계속 존재합니다.

 

 

Share data between fragments

 

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(requireActivity()).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(requireActivity()).get(SharedViewModel.class);
        model.getSelected().observe(getViewLifecycleOwner(), { item ->
           // Update the UI.
        });
    }
}

 

 

두 fragment 는 이 activity 로 범위가 지정된 같은 SharedViewModel 인스턴스를 얻습니다.

이러한 방법으로 얻는 이점:
1. activity 는 이 커뮤니케이션에 대해서 아무것도 알 필요가 없다.
2. fragment 는 SharedViewModel 이외에 서로에 대해서 알 필요가 없다. 한 fragment 사라져도 다른 fragment 계속 유지된다.
3. 각 fragment 는 자신만의 lifecycle 를 가지고 다른 lifecycle 에 영향받지 않는다. 한 fragment 가 replace 되더라도 UI 는 아무 문제 없이 계속 유지된다.

Related posts

Leave a Comment