/*
* Copyright (C) 2020 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dagger.hilt.android.internal.lifecycle;
import static androidx.lifecycle.SavedStateHandleSupport.createSavedStateHandle;
import android.app.Activity;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.viewmodel.CreationExtras;
import androidx.savedstate.SavedStateRegistryOwner;
import dagger.Module;
import dagger.hilt.EntryPoint;
import dagger.hilt.EntryPoints;
import dagger.hilt.InstallIn;
import dagger.hilt.android.components.ActivityComponent;
import dagger.hilt.android.components.ViewModelComponent;
import dagger.hilt.android.internal.builders.ViewModelComponentBuilder;
import dagger.multibindings.Multibinds;
import java.util.Map;
import javax.inject.Provider;
import kotlin.jvm.functions.Function1;
/**
* View Model Provider Factory for the Hilt Extension.
*
*
A provider for this factory will be installed in the {@link
* dagger.hilt.android.components.ActivityComponent} and {@link
* dagger.hilt.android.components.FragmentComponent}. An instance of this factory will also be the
* default factory by activities and fragments annotated with {@link
* dagger.hilt.android.AndroidEntryPoint}.
*/
public final class HiltViewModelFactory implements ViewModelProvider.Factory {
/** Hilt entry point for getting the multi-binding map of ViewModels. */
@EntryPoint
@InstallIn(ViewModelComponent.class)
public interface ViewModelFactoriesEntryPoint {
@HiltViewModelMap
Map, Provider> getHiltViewModelMap();
// From ViewModel class names to user defined @AssistedFactory-annotated implementations.
@HiltViewModelAssistedMap
Map, Object> getHiltViewModelAssistedMap();
}
/** Creation extra key for the callbacks that create @AssistedInject-annotated ViewModels. */
public static final CreationExtras.Key> CREATION_CALLBACK_KEY =
new CreationExtras.Key>() {};
/** Hilt module for providing the empty multi-binding map of ViewModels. */
@Module
@InstallIn(ViewModelComponent.class)
interface ViewModelModule {
@Multibinds
@HiltViewModelMap
Map, ViewModel> hiltViewModelMap();
@Multibinds
@HiltViewModelAssistedMap
Map, Object> hiltViewModelAssistedMap();
}
private final Map, Boolean> hiltViewModelKeys;
private final ViewModelProvider.Factory delegateFactory;
private final ViewModelProvider.Factory hiltViewModelFactory;
public HiltViewModelFactory(
@NonNull Map, Boolean> hiltViewModelKeys,
@NonNull ViewModelProvider.Factory delegateFactory,
@NonNull ViewModelComponentBuilder viewModelComponentBuilder) {
this.hiltViewModelKeys = hiltViewModelKeys;
this.delegateFactory = delegateFactory;
this.hiltViewModelFactory =
new ViewModelProvider.Factory() {
@NonNull
@Override
public T create(
@NonNull Class modelClass, @NonNull CreationExtras extras) {
RetainedLifecycleImpl lifecycle = new RetainedLifecycleImpl();
ViewModelComponent component =
viewModelComponentBuilder
.savedStateHandle(createSavedStateHandle(extras))
.viewModelLifecycle(lifecycle)
.build();
T viewModel = createViewModel(component, modelClass, extras);
viewModel.addCloseable(lifecycle::dispatchOnCleared);
return viewModel;
}
private T createViewModel(
@NonNull ViewModelComponent component,
@NonNull Class modelClass,
@NonNull CreationExtras extras) {
Provider extends ViewModel> provider =
EntryPoints.get(component, ViewModelFactoriesEntryPoint.class)
.getHiltViewModelMap()
.get(modelClass);
Function1