티스토리 뷰

반응형

Stack Overflow에 자주 검색, 등록되는 문제들과 제가 개발 중 찾아 본 문제들 중에서 나중에도 찾아 볼 것 같은 문제들을 정리하고 있습니다.

Stack Overflow에서 가장 먼저 확인하게 되는 가장 높은 점수를 받은 Solution과 현 시점에 도움이 될 수 있는 가장 최근에 업데이트(최소 점수 확보)된 Solution을 각각 정리하였습니다.

 

아래 word cloud를 통해 이번 포스팅의 주요 키워드를 미리 확인하세요.

Android ViewModel additional arguments

안드로이드 ViewModel 추가 인수

 문제 내용 

Is there a way to pass additional argument to my custom AndroidViewModel constructor except Application context. Example:

안드로이드 뷰모델(Andoird ViewModel) 생성자에 애플리케이션 컨텍스트 이외의 추가 인수를 전달하는 방법이 있을까요? 예를 들어, 다음과 같이 구현한 뷰모델 생성자에게 추가 인수를 전달하려면 어떻게 해야 할까요?
public class MyViewModel extends AndroidViewModel {
    private final LiveData<List<MyObject>> myObjectList;
    private AppDatabase appDatabase;

    public MyViewModel(Application application, String param) {
        super(application);
        appDatabase = AppDatabase.getDatabase(this.getApplication());

        myObjectList = appDatabase.myOjectModel().getMyObjectByParam(param);
    }
}

 

And when I want to user my custom ViewModel class I use this code in my fragment:

그리고 제가 만든 ViewModel 클래스를 사용하려면, 저는 제 프래그먼트에서 이 코드를 사용합니다:
MyViewModel myViewModel = ViewModelProvider.of(this).get(MyViewModel.class)

 

So I don't know how to pass additional argument String param into my custom ViewModel. I can only pass Application context, but not additional arguments. I would really appreciate any help. Thank you.

그래서 추가 인수(String param)를 제 맞춤형 ViewModel에 전달하는 방법을 모르겠습니다. Application context만 전달할 수 있지만 추가 인수는 전달할 수 없습니다. 어떤 도움이든 정말 감사하겠습니다. 감사합니다.

 

Edit: I've added some code. I hope it's better now.

수정: 몇 가지 코드를 추가했습니다. 이제 더 나은 이해가 가능할 것입니다.

 

 

 

 높은 점수를 받은 Solution 

You need to have a factory class for your ViewModel.

당신은 ViewModel을 위한 팩토리 클래스가 필요합니다.
public class MyViewModelFactory implements ViewModelProvider.Factory {
    private Application mApplication;
    private String mParam;


    public MyViewModelFactory(Application application, String param) {
        mApplication = application;
        mParam = param;
    }


    @Override
    public <T extends ViewModel> T create(Class<T> modelClass) {
        return (T) new MyViewModel(mApplication, mParam);
    }
}

 

And when instantiating the view model, you do like this:

그리고 뷰모델을 인스턴스화할 때, 다음과 같이합니다.
MyViewModel myViewModel = ViewModelProvider(this, new MyViewModelFactory(this.getApplication(), "my awesome param")).get(MyViewModel.class);

 

For kotlin, you may use delegated property:

코틀린에서는 위임된 프로퍼티를 사용할 수 있습니다.
val viewModel: MyViewModel by viewModels { MyViewModelFactory(getApplication(), "my awesome param") }

 

There's also another new option - to implement HasDefaultViewModelProviderFactory and override getDefaultViewModelProviderFactory() with the instantiation of your factory and then you would call ViewModelProvider(this) or by viewModels() without the factory.

또 다른 새로운 옵션으로는 HasDefaultViewModelProviderFactory를 구현하고 getDefaultViewModelProviderFactory()를 재정의하여 팩토리를 인스턴스화한 다음에는 팩토리없이 ViewModelProvider(this) 또는 viewModels()를 호출할 수 있습니다.

 

 

 

 가장 최근 달린 Solution 

The proper way is to use a dependency injection framework such as Dagger hilt. If not using a DI framework, then do it with ViewModelFactory.

적절한 방법은 Dagger hilt와 같은 의존성 주입 프레임워크를 사용하는 것입니다. DI 프레임워크를 사용하지 않을 경우에는 ViewModelFactory를 사용해야 합니다.

 

With Dagger Hilt:

Dagger Hilt를 사용하는 경우:

 

A ViewModel with parameters

매개 변수가 있는 ViewModel
@HiltViewModel
class MyViewModel @Inject constructor(
    private val myRepository: MyRepository,
    private val savedStateHandle: SavedStateHandle
) : ViewModel() { ... }

 

A Repository

class MyRepository @Inject constructor(
    private val myRemoteDataSource: MyDataSource,
    private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
) { ... }

 

A Module for providing the dependencies/parameters so they can be injected into repositories and ViewModels.

의존성/매개변수를 제공하여 리포지토리 및 뷰모델에 주입할 수 있도록하는 모듈(Module)입니다.
@InstallIn(ViewModelComponent::class)
@Module
object MyProvideModule {
    @Provides
    fun provideMyDataSource(@ApplicationContext context: Context): MyDataSource {
        //code to create MyDataSource... 
        return MyDataSource(context)
    }

    @Provides
    fun provideCoroutineDispatcher(): CoroutineDispatcher {
        return Dispatchers.IO
    }
}

 

A module for binding the repository

리포지토리 바인딩을 위한 모듈(Module)
@Module
@InstallIn(ViewModelComponent::class)
interface RepositoryModules {
    @Binds
    fun provideMyRepository(repository: MyRepository): MyRepository
}

 

Initiating Dagger hilt with the application with the @HiltAndroidApp annotation.

@HiltAndroidApp 어노테이션을 사용하여 애플리케이션과 Dagger Hilt를 초기화합니다.
@HiltAndroidApp
class MainApplication : Application() {

    override fun onCreate() {
        super.onCreate()
    }

}

 

Getting the ViewModel in activities

액티비티에서 ViewModel 가져오기
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
  private val myViewModel: MyViewModel by viewModels()
  // Other code...
}

 

Getting the ViewModel in fragments

프래그먼트에서 ViewModel 가져오기
@AndroidEntryPoint
class MyFragment : Fragment() {
  private val myViewModel: MyViewModel by activityViewModels()
  // Other code...
}

 

With ViewModelFactory:

ViewModelFactory를 사용하는 방법:

 

A ViewModel with parameter messageDataStore, where MessageDataStore is a DataStore class or it can be anything else that you want to pass into the ViewModel.

MessageDataStore가 DataStore 클래스이거나 ViewModel에 전달하려는 다른 것일 수 있는 매개변수 messageDataStore가 있는 ViewModel입니다.
class MyViewModel(
    private val messageDataStore: MessageDataStore,
): ViewModel() { ... }

 

The ViewModel factory class for creating ViewModels

ViewModel을 생성하기 위한 ViewModel 팩토리 클래스
/**
 * Factory for all ViewModels.
 */
@Suppress("UNCHECKED_CAST")
class ViewModelFactory constructor(
    private val messageDataStore: MessageDataStore,
    owner: SavedStateRegistryOwner,
    defaultArgs: Bundle? = null
) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
    override fun <T : ViewModel> create(
        key: String,
        modelClass: Class<T>,
        handle: SavedStateHandle
    ) = with(modelClass) {
        when {
            isAssignableFrom(MyViewModel::class.java) ->
                MyViewModel(messageDataStore)
            else ->
                throw IllegalArgumentException("Unknown ViewModel class: ${modelClass.name}")
        }
    } as T
}

 

The application class for creating the dependencies/parameters

의존성/매개 변수를 생성하기 위한 애플리케이션 클래스
class MyApp : Application() {
    val messageDataStore: MessageDataStore
        get() = MessageDataStore.getInstance(this)

}

 

Extension functions for getting the factory class in activities and fragments, MyExt.kt

액티비티 및 프래그먼트에서 팩토리 클래스를 가져오기위한 확장 함수, MyExt.kt
fun AppCompatActivity.getViewModelFactory(savedInstanceState: Bundle?): ViewModelFactory {
    val messageDataStore = (applicationContext as MyApp).messageDataStore
    return ViewModelFactory(messageDataStore, this, savedInstanceState)
}

fun Fragment.getViewModelFactory(savedInstanceState: Bundle?): ViewModelFactory {
    val messageDataStore = (requireContext().applicationContext as MyApp).messageDataStore
    return ViewModelFactory(messageDataStore, this.requireActivity(), savedInstanceState)
}

 

Getting the ViewMode in activities

액티비티에서 ViewModel 가져오기
class MainActivity : AppCompatActivity() {

  private lateinit var myViewModel: MyViewModel
  // Other code...

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val vm by viewModels<MyViewModel> { getViewModelFactory(savedInstanceState) }
    myViewModel = vm
    // Other code...
  }
}

 

Getting the ViewModel in Fragments.

Fragment에서 ViewModel 가져오기
class MyFragment : Fragment() {
    private lateinit var myViewModel: MyViewModel
    //Other code...

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
      val vm by activityViewModels<MyViewModel> { getViewModelFactory(savedInstanceState) }
      myViewModel = vm
      //Other code...
  }
}

 

 

출처 : https://stackoverflow.com/questions/46283981/android-viewmodel-additional-arguments

반응형
댓글
공지사항
최근에 올라온 글