Creare ViewModel con dipendenze (Views) Parte di Android Jetpack.
Concetti e implementazione di Jetpack Compose
Seguendo le best practice dell'iniezione delle dipendenze, i ViewModel possono
accettare dipendenze come parametri nel loro costruttore. Si tratta per lo più di tipi
dei livelli didominio o dati. Poiché il framework fornisce i ViewModel, è necessario un meccanismo speciale per crearne le istanze. Questo meccanismo è l'interfaccia ViewModelProvider.Factory. Solo le implementazioni di questa interfaccia possono creare istanze di ViewModel nell'ambito corretto.
ViewModel con CreationExtras
Se una classe ViewModel riceve dipendenze nel suo costruttore, fornisci una
factory che implementa l'interfaccia ViewModelProvider.Factory.
Esegui l'override della create(Class<T>, CreationExtras) funzione per fornire una
nuova istanza del ViewModel.
CreationExtras con APPLICATION_KEY
Di seguito è riportato un esempio di come fornire un'istanza di un ViewModel che
accetta un repository con ambito alla classe Application e
SavedStateHandle come dipendenze:
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);
}
);
}
Dopodiché, puoi utilizzare questa factory quando recuperi un'istanza del 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
}
Trasmettere parametri personalizzati come CreationExtras
Puoi trasmettere le dipendenze al tuo ViewModel tramite CreationExtras creando una chiave personalizzata.
Questa operazione può essere utile se il tuo ViewModel dipende da oggetti a cui non è possibile accedere tramite la classe Application e APPLICATION_KEY. Un esempio è quando il ViewModel viene creato all'interno di un modulo Kotlin Multiplatform e pertanto non ha accesso alle dipendenze di Android.
In questo esempio, il ViewModel definisce una chiave personalizzata e la utilizza in the
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,
)
}
}
}
}
Puoi creare un'istanza di un ViewModel con un CreationExtras.Key da un
ViewModelStoreOwner come
ComponentActivity, Fragment, o NavBackStackEntry.
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]
Factory per la versione di ViewModel precedente alla 2.5.0
Se utilizzi una versione di ViewModel precedente alla 2.5.0, devi fornire
le factory da un sottoinsieme di classi che estendono ViewModelProvider.Factory
e implementano la funzione create(Class<T>). A seconda delle dipendenze richieste da ViewModel, è necessario estendere una classe diversa:
AndroidViewModelFactoryse è necessaria la classeApplication.AbstractSavedStateViewModelFactoryseSavedStateHandledeve essere trasmesso come dipendenza.
Se Application o SavedStateHandle non sono necessari, estendi semplicemente da ViewModelProvider.Factory.
L'esempio seguente utilizza un AbstractSavedStateViewModelFactory per un
ViewModel che accetta un repository e un tipo SavedStateHandle come dipendenza:
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);
}
}
Dopodiché, puoi utilizzare la factory per recuperare il 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
}
Consigliati per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Modulo Stato salvato per ViewModel
- Salvare gli stati dell'interfaccia utente
- Panoramica di LiveData