티스토리 뷰
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
'개발 > 안드로이드' 카테고리의 다른 글
Android Webview: "Uncaught TypeError: Cannot read property 'getItem' of null" 수정하기 (0) | 2023.02.17 |
---|---|
Activity의 content view를 가져오기 (0) | 2023.02.17 |
안드로이드에서 사용자 지정 뷰의 높이와 너비를 프로그래밍 방식으로 설정하기 (0) | 2023.02.16 |
안드로이드 WebView에서 JavaScript가 작동하지 않을 때 해결 방법 (0) | 2023.02.16 |
Android MVVM ViewModel에서 Context 얻기 (0) | 2023.02.15 |