종속 항목이 있는 ViewModel 만들기 Android Jetpack의 구성요소
종속 항목 삽입의 권장사항에 따라 ViewModel은 종속 항목을 생성자의 매개변수로 사용할 수 있습니다. 이는 대부분 도메인 또는 데이터 레이어의 유형입니다. 프레임워크에서 ViewModel을 제공하기 때문에 ViewModel의 인스턴스를 만들려면 특수한 메커니즘이 필요합니다. 이 메커니즘이 ViewModelProvider.Factory 인터페이스입니다. 이 인터페이스의 구현만 올바른 범위에서 ViewModel을 인스턴스화할 수 있습니다.
CreationExtras가 포함된 ViewModel
ViewModel 클래스가 생성자의 종속 항목을 수신하면 ViewModelProvider.Factory 인터페이스를 구현하는 팩토리를 제공합니다.
ViewModel의 새 인스턴스를 제공하도록 create(Class<T>, CreationExtras) 함수를 재정의합니다.
CreationExtras를 사용하면 ViewModel을 인스턴스화하는 데 유용한 관련 정보에 액세스할 수 있습니다. Extras에서 액세스할 수 있는 키 목록은 다음과 같습니다.
| 키 | 기능 | 
|---|---|
| ViewModelProvider.NewInstanceFactory.VIEW_MODEL_KEY | ViewModelProvider.get()에 전달한 맞춤 키에 대한 액세스 권한을 제공합니다. | 
| ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY | Application클래스의 인스턴스에 대한 액세스 권한을 제공합니다. | 
| SavedStateHandleSupport.DEFAULT_ARGS_KEY | SavedStateHandle을 구성하는 데 사용해야 하는 인수의 Bundle에 대한 액세스 권한을 제공합니다. | 
| SavedStateHandleSupport.SAVED_STATE_REGISTRY_OWNER_KEY | ViewModel을 구성하는 데 사용되는SavedStateRegistryOwner에 대한 액세스 권한을 제공합니다. | 
| SavedStateHandleSupport.VIEW_MODEL_STORE_OWNER_KEY | ViewModel을 구성하는 데 사용되는ViewModelStoreOwner에 대한 액세스 권한을 제공합니다. | 
SavedStateHandle의 새 인스턴스를 만들려면 CreationExtras.createSavedStateHandle() 함수를 사용하여 ViewModel에 전달합니다.
APPLICATION_KEY가 있는 CreationExtras
다음은 Application 클래스 및 SavedStateHandle로 범위가 지정된 저장소를 종속 항목으로 사용하는 ViewModel의 인스턴스를 제공하는 방법을 보여 주는 예입니다.
Kotlin
    import androidx.lifecycle.SavedStateHandle
    import androidx.lifecycle.ViewModel
    import androidx.lifecycle.ViewModelProvider
    import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY
    import androidx.lifecycle.createSavedStateHandle
    import androidx.lifecycle.viewmodel.CreationExtras
    class MyViewModel(
        private val myRepository: MyRepository,
        private val savedStateHandle: SavedStateHandle
    ) : ViewModel() {
        // ViewModel logic
        // ...
        // Define ViewModel factory in a companion object
        companion object {
            val Factory: ViewModelProvider.Factory = object : ViewModelProvider.Factory {
                @Suppress("UNCHECKED_CAST")
                override fun <T : ViewModel> create(
                    modelClass: Class<T>,
                    extras: CreationExtras
                ): T {
                    // Get the Application object from extras
                    val application = checkNotNull(extras[APPLICATION_KEY])
                    // Create a SavedStateHandle for this ViewModel from extras
                    val savedStateHandle = extras.createSavedStateHandle()
                    return MyViewModel(
                        (application as MyApplication).myRepository,
                        savedStateHandle
                    ) as T
                }
            }
        }
    }
자바
import static androidx.lifecycle.SavedStateHandleSupport.createSavedStateHandle;
import static androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY;
import androidx.lifecycle.SavedStateHandle;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.viewmodel.ViewModelInitializer;
public class MyViewModel extends ViewModel {
    public MyViewModel(
        MyRepository myRepository,
        SavedStateHandle savedStateHandle
    ) { /* Init ViewModel here */ }
    static final ViewModelInitializer<MyViewModel> initializer = new ViewModelInitializer<>(
        MyViewModel.class,
        creationExtras -> {
            MyApplication app = (MyApplication) creationExtras.get(APPLICATION_KEY);
            assert app != null;
            SavedStateHandle savedStateHandle = createSavedStateHandle(creationExtras);
            return new MyViewModel(app.getMyRepository(), savedStateHandle);
        }
    );
}
그런 다음 ViewModel의 인스턴스를 가져올 때 이 팩토리를 사용할 수 있습니다.
Kotlin
import androidx.activity.viewModels
class MyActivity : AppCompatActivity() {
    private val viewModel: MyViewModel by viewModels { MyViewModel.Factory }
    // Rest of Activity code
}
Java
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
public class MyActivity extends AppCompatActivity {
MyViewModel myViewModel = new ViewModelProvider(
    this,
    ViewModelProvider.Factory.from(MyViewModel.initializer)
).get(MyViewModel.class);
// Rest of Activity code
}
Jetpack Compose
import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun MyScreen(
    modifier: Modifier = Modifier,
    viewModel: MyViewModel = viewModel(factory = MyViewModel.Factory)
) {
    // ...
}
또는 ViewModel 팩토리 DSL을 사용하여 더 자연스러운 Kotlin API로 팩토리를 만듭니다.
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY
import androidx.lifecycle.createSavedStateHandle
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
class MyViewModel(
    private val myRepository: MyRepository,
    private val savedStateHandle: SavedStateHandle
) : ViewModel() {
    // ViewModel logic
    // Define ViewModel factory in a companion object
    companion object {
        val Factory: ViewModelProvider.Factory = viewModelFactory {
            initializer {
                val savedStateHandle = createSavedStateHandle()
                val myRepository = (this[APPLICATION_KEY] as MyApplication).myRepository
                MyViewModel(
                    myRepository = myRepository,
                    savedStateHandle = savedStateHandle
                )
            }
        }
    }
}
맞춤 매개변수를 CreationExtras로 전달
커스텀 키를 만들어 CreationExtras를 통해 ViewModel에 종속 항목을 전달할 수 있습니다.
이 기능은 ViewModel이 Application 클래스 및 APPLICATION_KEY를 통해 액세스할 수 없는 객체에 의존하는 경우 유용할 수 있습니다. 예를 들어 ViewModel가 Kotlin 멀티플랫폼 모듈 내에서 생성되어 Android 종속 항목에 액세스할 수 없는 경우를 들 수 있습니다.
이 예에서 ViewModel는 맞춤 키를 정의하고 ViewModelProvider.Factory에서 이를 사용합니다.
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
class MyViewModel(
    private val myRepository: MyRepository,
) : ViewModel() {
    // ViewModel logic
    // Define ViewModel factory in a companion object
    companion object {
        // Define a custom key for your dependency
        val MY_REPOSITORY_KEY = object : CreationExtras.Key<MyRepository> {}
        val Factory: ViewModelProvider.Factory = viewModelFactory {
            initializer {
                // Get the dependency in your factory
                val myRepository = this[MY_REPOSITORY_KEY] as MyRepository
                MyViewModel(
                    myRepository = myRepository,
                )
            }
        }
    }
}
ComponentActivity, Fragment, NavBackStackEntry와 같은 ViewModelStoreOwner에서 CreationExtras.Key를 사용하여 ViewModel를 인스턴스화하거나 Jetpack Compose를 사용하여 ViewModel를 인스턴스화할 수 있습니다.
Kotlin
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStoreOwner
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.MutableCreationExtras
// ...
    // Use from ComponentActivity, Fragment, NavBackStackEntry,
    // or another ViewModelStoreOwner.
    val viewModelStoreOwner: ViewModelStoreOwner = this
    val myViewModel: MyViewModel = ViewModelProvider.create(
        viewModelStoreOwner,
        factory = MyViewModel.Factory,
        extras = MutableCreationExtras().apply {
            set(MyViewModel.MY_REPOSITORY_KEY, myRepository)
        },
    )[MyViewModel::class]
Jetpack Compose
import androidx.lifecycle.viewmodel.MutableCreationExtras
import androidx.lifecycle.viewmodel.compose.viewModel
// ...
@Composable
fun MyApp(myRepository: MyRepository) {
    val extras = MutableCreationExtras().apply {
        set(MyViewModel.MY_REPOSITORY_KEY, myRepository)
    }
    val viewModel: MyViewModel = viewModel(
        factory = MyViewModel.Factory,
        extras = extras,
    )
}
2.5.0 이전의 ViewModel 버전에 대한 팩토리
2.5.0 이전 버전의 ViewModel를 사용하는 경우 ViewModelProvider.Factory를 확장하는 클래스의 하위 집합에서 팩토리를 제공하고 create(Class<T>) 함수를 구현해야 합니다. ViewModel에 필요한 종속 항목에 따라 다음에서 다른 클래스를 확장해야 합니다.
- Application클래스가 필요한 경우- AndroidViewModelFactory
- SavedStateHandle을 종속 항목으로 전달해야 하는 경우- AbstractSavedStateViewModelFactory
Application 또는 SavedStateHandle이 필요하지 않으면 ViewModelProvider.Factory에서 확장합니다.
다음 예에서는 저장소 및 SavedStateHandle 유형을 종속 항목으로 사용하는 ViewModel에 대해 AbstractSavedStateViewModelFactory를 사용합니다.
Kotlin
class MyViewModel(
private val myRepository: MyRepository,
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
// ViewModel logic ...
// Define ViewModel factory in a companion object
companion object {
    fun provideFactory(
        myRepository: MyRepository,
        owner: SavedStateRegistryOwner,
        defaultArgs: Bundle? = null,
    ): AbstractSavedStateViewModelFactory =
        object : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
            @Suppress("UNCHECKED_CAST")
            override fun <T : ViewModel> create(
                key: String,
                modelClass: Class<T>,
                handle: SavedStateHandle
            ): T {
                return MyViewModel(myRepository, handle) as T
            }
        }
    }
}
Java
import androidx.annotation.NonNull;
import androidx.lifecycle.AbstractSavedStateViewModelFactory;
import androidx.lifecycle.SavedStateHandle;
import androidx.lifecycle.ViewModel;
public class MyViewModel extends ViewModel {
    public MyViewModel(
        MyRepository myRepository,
        SavedStateHandle savedStateHandle
    ) { /* Init ViewModel here */ }
}
public class MyViewModelFactory extends AbstractSavedStateViewModelFactory {
    private final MyRepository myRepository;
    public MyViewModelFactory(
        MyRepository myRepository
    ) {
        this.myRepository = myRepository;
    }
    @SuppressWarnings("unchecked")
    @NonNull
    @Override
    protected <T extends ViewModel> T create(
        @NonNull String key, @NonNull Class<T> modelClass, @NonNull SavedStateHandle handle
    ) {
        return (T) new MyViewModel(myRepository, handle);
    }
}
그런 다음 팩토리를 사용하여 ViewModel을 가져올 수 있습니다.
Kotlin
import androidx.activity.viewModels
class MyActivity : AppCompatActivity() {
    private val viewModel: MyViewModel by viewModels {
        MyViewModel.provideFactory((application as MyApplication).myRepository, this)
    }
    // Rest of Activity code
}
Java
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
public class MyActivity extends AppCompatActivity {
    MyViewModel myViewModel = new ViewModelProvider(
        this,
        ViewModelProvider.Factory.from(MyViewModel.initializer)
    ).get(MyViewModel.class);
    // Rest of Activity code
}
Jetpack Compose
import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun MyScreen(
    modifier: Modifier = Modifier,
    viewModel: MyViewModel = viewModel(
        factory = MyViewModel.provideFactory(
            (LocalContext.current.applicationContext as MyApplication).myRepository,
            owner = LocalSavedStateRegistryOwner.current
        )
    )
) {
    // ...
}
추천 서비스
- 참고: JavaScript가 사용 중지되어 있으면 링크 텍스트가 표시됩니다.
- ViewModel의 저장된 상태 모듈
- UI 상태 저장
- LiveData 개요
