[android] Android MVVM ViewModel에서 컨텍스트를 얻는 방법

내 Android 앱에서 MVVM 패턴을 구현하려고합니다. ViewModels에 안드로이드 특정 코드가 포함되어서는 안된다는 것을 읽었지만 (테스트를 더 쉽게하기 위해), 여러 가지 (xml에서 리소스 가져 오기, 기본 설정 초기화 등)에 컨텍스트를 사용해야합니다. 이를 수행하는 가장 좋은 방법은 무엇입니까? I 톱 AndroidViewModel내가하지 않도록 그 뷰 모델에 있어야하는 경우 해요 있도록 애플리케이션 컨텍스트에 대한 참조를 가지고, 그러나 그것은 안드로이드 특정 코드가 포함되어 있습니다. 또한 그것들은 활동 라이프 사이클 이벤트와 연결되지만, 구성 요소의 범위를 관리하기 위해 단검을 사용하고 있으므로 그것이 어떻게 영향을 미칠지 잘 모르겠습니다. 저는 MVVM 패턴과 Dagger를 처음 사용하므로 도움을 주시면 감사하겠습니다!



답변

에서 Application제공 하는 컨텍스트를 사용할 수 있으며 단순히 참조 를 포함하는 AndroidViewModel확장해야합니다 .AndroidViewModelViewModelApplication


답변

Android 아키텍처 구성 요소보기 모델의 경우

메모리 누수로 인해 Activity Context를 Activity의 ViewModel에 전달하는 것은 좋은 습관이 아닙니다.

따라서 ViewModel에서 컨텍스트를 얻으려면 ViewModel 클래스가 Android View Model 클래스를 확장해야합니다 . 이렇게하면 아래 예제 코드와 같이 컨텍스트를 얻을 수 있습니다.

class ActivityViewModel(application: Application) : AndroidViewModel(application) {

    private val context = getApplication<Application>().applicationContext

    //... ViewModel methods

}


답변

ViewModels에 테스트를 더 쉽게 만드는 Android 특정 코드가 포함되어서는 안됩니다.

ViewModels에 Context 인스턴스 또는 Context를 유지하는 뷰 또는 기타 개체와 같은 항목이 포함되어서는 안되는 이유는 활동 및 조각과는 별도의 수명주기가 있기 때문입니다.

이것이 의미하는 바는 앱에서 회전 변경을한다고 가정 해 봅시다. 이로 인해 활동과 조각이 스스로 파괴되어 스스로를 다시 만듭니다. ViewModel은이 상태 동안 지속되도록되어 있으므로 파괴 된 Activity에 대한 View 또는 Context를 여전히 보유하고있는 경우 충돌 및 기타 예외가 발생할 가능성이 있습니다.

원하는 작업을 수행하는 방법에 관해서는 MVVM 및 ViewModel이 JetPack의 데이터 바인딩 구성 요소와 잘 작동합니다. 일반적으로 String, int 등을 저장하는 대부분의 경우 Databinding을 사용하여 View가 직접 표시하도록 할 수 있으므로 ViewModel 내에 값을 저장할 필요가 없습니다.

그러나 데이터 바인딩을 원하지 않는 경우 생성자 또는 메서드 내부에 Context를 전달하여 리소스에 액세스 할 수 있습니다. ViewModel 내부에 해당 컨텍스트의 인스턴스를 보유하지 마십시오.


답변

짧은 대답-하지 마십시오

왜 ?

뷰 모델의 전체 목적을 무너 뜨립니다.

뷰 모델에서 수행 할 수있는 거의 모든 작업은 LiveData 인스턴스 및 기타 다양한 권장 접근 방식을 사용하여 활동 / 단편에서 수행 할 수 있습니다.


답변

ViewModel에서 직접 Context를 사용하는 대신 수행 한 작업은 필요한 리소스를 제공하는 ResourceProvider와 같은 공급자 클래스를 만들고 ViewModel에 해당 공급자 클래스를 삽입했습니다.


답변

요약 : ViewModels에서 Dagger를 통해 애플리케이션의 컨텍스트를 주입하고이를 사용하여 리소스를로드합니다. 이미지를로드해야하는 경우 Databinding 메서드의 인수를 통해 View 인스턴스를 전달하고 해당 View 컨텍스트를 사용합니다.

MVVM은 좋은 아키텍처이며 확실히 Android 개발의 미래이지만 여전히 녹색 인 몇 가지 사항이 있습니다. 예를 들어 MVVM 아키텍처의 계층 통신을 살펴보면 여러 개발자 (아주 잘 알려진 개발자)가 LiveData를 사용하여 서로 다른 방식으로 서로 다른 계층을 통신하는 것을 보았습니다. 그들 중 일부는 LiveData를 사용하여 ViewModel을 UI와 통신하지만 콜백 인터페이스를 사용하여 Repositories와 통신하거나 Interactors / UseCases가 있고 LiveData를 사용하여 통신합니다. 여기서 요점은 모든 것이 아직 100 % 정의 된 것은 아니라는 것입니다 .

즉, 특정 문제에 대한 내 접근 방식은 DI를 통해 응용 프로그램의 컨텍스트를 사용하여 내 ViewModel에서 사용하여 strings.xml에서 String과 같은 것을 가져 오는 것입니다.

이미지로드를 처리하는 경우 데이터 바인딩 어댑터 메서드에서 View 개체를 전달하고 View의 컨텍스트를 사용하여 이미지를로드하려고합니다. 왜? 일부 기술 (예 : Glide)은 애플리케이션의 컨텍스트를 사용하여 이미지를로드하는 경우 문제가 발생할 수 있기 때문입니다.

도움이 되었기를 바랍니다.


답변

다른 사람들이 언급했듯이 AndroidViewModel앱을 얻기 위해 파생 할 수있는 Context것이 있지만 주석에서 수집 한 내용에서 MVVM 목적을 무력화하는 @drawables 를 조작하려고합니다 ViewModel.

일반적으로를 가지고 있어야한다는 Context것은 ViewModel거의 보편적으로 Views와 ViewModels.

ViewModel드로어 블 을 해결하고이를 Activity / Fragment에 공급하는 대신 Fragment / Activity가 .NET Core가 소유 한 데이터를 기반으로 드로어 블을 저글링하도록하는 것이 ViewModel좋습니다. on / off 상태에 대한 뷰에 다른 드로어 블을 표시해야한다고 가정 해 보겠습니다. ViewModel이는 (아마도 부울) 상태를 유지해야하지만 View그에 따라 드로어 블을 선택하는 것이 몫입니다.

DataBinding으로 매우 쉽게 수행 할 수 있습니다 .

<ImageView
...
app:src="@{viewModel.isOn ? @drawable/switch_on : @drawable/switch_off}"
/>

상태와 드로어 블이 더 많은 경우 레이아웃 파일의 다루기 힘든 논리를 피하기 위해 값을 (예 : 카드 슈트) 로 변환 하는 사용자 정의 BindingAdapter 를 작성할 수 있습니다.EnumR.drawable.*

또는 Context내부에서 사용하는 일부 구성 요소가 필요할 수 있습니다. ViewModel그런 다음 외부에서 구성 요소를 만들고 ViewModel전달합니다. DI 또는 싱글 톤을 사용하거나 in /을 Context초기화하기 직전에 종속 구성 요소를 만들 수 있습니다 .ViewModelFragmentActivity

귀찮은 이유 : Context는 Android 전용이며 ViewModels 에있는 항목에 따라 달라지는 것은 좋지 않습니다. 단위 테스트를 방해합니다. 반면에 자신의 구성 요소 / 서비스 인터페이스는 완전히 제어 할 수 있으므로 테스트를 위해 쉽게 모의 할 수 있습니다.