ViewModels mit Abhängigkeiten erstellen (Ansichten)   Teil von Android Jetpack.

Konzepte und Jetpack Compose-Implementierung

Gemäß den Best Practices für die Abhängigkeitsinjektion können ViewModels Abhängigkeiten als Parameter in ihrem Konstruktor verwenden. Dabei handelt es sich meist um Typen aus den Domain- oder Datenschichten. Da das Framework die ViewModels bereitstellt, ist ein spezieller Mechanismus erforderlich, um Instanzen davon zu erstellen. Dieser Mechanismus ist die ViewModelProvider.Factory-Schnittstelle. Nur Implementierungen dieser Schnittstelle können ViewModels im richtigen Bereich instanziieren.

ViewModels mit CreationExtras

Wenn eine ViewModel-Klasse Abhängigkeiten in ihrem Konstruktor empfängt, stellen Sie eine Factory bereit, die die ViewModelProvider.Factory-Schnittstelle implementiert. Überschreiben Sie die create(Class<T>, CreationExtras) Funktion, um eine neue Instanz des ViewModel bereitzustellen.

CreationExtras mit APPLICATION_KEY

Im Folgenden finden Sie ein Beispiel dafür, wie Sie eine Instanz eines ViewModel bereitstellen, das ein Repository mit dem Bereich der Application Klasse und SavedStateHandle als Abhängigkeiten verwendet:

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);
        }
    );
}

Anschließend können Sie diese Factory verwenden, wenn Sie eine Instanz des ViewModel abrufen:

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
}

Benutzerdefinierte Parameter als CreationExtras übergeben

Sie können Abhängigkeiten über CreationExtras an Ihr ViewModel übergeben, indem Sie einen benutzerdefinierten Schlüssel erstellen. Das kann nützlich sein, wenn Ihr ViewModel von Objekten abhängt, auf die nicht über die Application-Klasse und APPLICATION_KEY zugegriffen werden kann. Ein Beispiel dafür ist, wenn Ihr ViewModel in einem Kotlin Multiplatform-Modul erstellt wird und daher keinen Zugriff auf Android-Abhängigkeiten hat.

In diesem Beispiel definiert das ViewModel einen benutzerdefinierten Schlüssel und verwendet ihn in der 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,
                )
            }
        }
    }
}

Sie können ein ViewModel mit einem CreationExtras.Key aus einem ViewModelStoreOwner wie ComponentActivity, Fragment, oder NavBackStackEntry instanziieren.

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]

Factories für ViewModel-Versionen vor 2.5.0

Wenn Sie eine Version von ViewModel vor 2.5.0 verwenden, müssen Sie Factories aus einer Teilmenge von Klassen bereitstellen, die ViewModelProvider.Factory erweitern und die Funktion create(Class<T>) implementieren. Je nachdem, welche Abhängigkeiten das ViewModel benötigt, muss eine andere Klasse erweitert werden:

Wenn Application oder SavedStateHandle nicht erforderlich sind, erweitern Sie einfach ViewModelProvider.Factory.

Im folgenden Beispiel wird eine AbstractSavedStateViewModelFactory für ein ViewModel verwendet, das ein Repository und einen SavedStateHandle-Typ als Abhängigkeit verwendet:

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);
    }
}

Anschließend können Sie die Factory verwenden, um Ihr ViewModel abzurufen:

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
}