1 /* 2 * Copyright (C) 2020 The Dagger Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package dagger.hilt.android.internal.lifecycle; 18 19 import android.app.Application; 20 import androidx.lifecycle.SavedStateViewModelFactory; 21 import androidx.lifecycle.ViewModelProvider; 22 import android.os.Bundle; 23 import androidx.annotation.Nullable; 24 import androidx.fragment.app.Fragment; 25 import androidx.activity.ComponentActivity; 26 import androidx.savedstate.SavedStateRegistryOwner; 27 import dagger.Module; 28 import dagger.hilt.EntryPoint; 29 import dagger.hilt.EntryPoints; 30 import dagger.hilt.InstallIn; 31 import dagger.hilt.android.components.ActivityComponent; 32 import dagger.hilt.android.components.FragmentComponent; 33 import dagger.hilt.android.internal.builders.ViewModelComponentBuilder; 34 import dagger.multibindings.Multibinds; 35 import java.util.Set; 36 import javax.inject.Inject; 37 38 /** 39 * Modules and entry points for the default view model factory used by activities and fragments 40 * annotated with @AndroidEntryPoint. 41 * 42 * <p>Entry points are used to acquire the factory because injected fields in the generated 43 * activities and fragments are ignored by Dagger when using the transform due to the generated 44 * class not being part of the hierarchy during compile time. 45 */ 46 public final class DefaultViewModelFactories { 47 48 /** 49 * Retrieves the default view model factory for the activity. 50 * 51 * <p>Do not use except in Hilt generated code! 52 */ getActivityFactory(ComponentActivity activity, ViewModelProvider.Factory delegateFactory)53 public static ViewModelProvider.Factory getActivityFactory(ComponentActivity activity, 54 ViewModelProvider.Factory delegateFactory) { 55 return EntryPoints.get(activity, ActivityEntryPoint.class) 56 .getHiltInternalFactoryFactory() 57 .fromActivity(activity, delegateFactory); 58 } 59 60 /** 61 * Retrieves the default view model factory for the activity. 62 * 63 * <p>Do not use except in Hilt generated code! 64 */ getFragmentFactory( Fragment fragment, ViewModelProvider.Factory delegateFactory)65 public static ViewModelProvider.Factory getFragmentFactory( 66 Fragment fragment, ViewModelProvider.Factory delegateFactory) { 67 return EntryPoints.get(fragment, FragmentEntryPoint.class) 68 .getHiltInternalFactoryFactory() 69 .fromFragment(fragment, delegateFactory); 70 } 71 72 /** Internal factory for the Hilt ViewModel Factory. */ 73 public static final class InternalFactoryFactory { 74 75 private final Application application; 76 private final Set<String> keySet; 77 private final ViewModelComponentBuilder viewModelComponentBuilder; 78 79 @Inject InternalFactoryFactory( Application application, @HiltViewModelMap.KeySet Set<String> keySet, ViewModelComponentBuilder viewModelComponentBuilder)80 InternalFactoryFactory( 81 Application application, 82 @HiltViewModelMap.KeySet Set<String> keySet, 83 ViewModelComponentBuilder viewModelComponentBuilder) { 84 this.application = application; 85 this.keySet = keySet; 86 this.viewModelComponentBuilder = viewModelComponentBuilder; 87 } 88 fromActivity( ComponentActivity activity, ViewModelProvider.Factory delegateFactory)89 ViewModelProvider.Factory fromActivity( 90 ComponentActivity activity, ViewModelProvider.Factory delegateFactory) { 91 return getHiltViewModelFactory( 92 activity, 93 activity.getIntent() != null ? activity.getIntent().getExtras() : null, 94 delegateFactory); 95 } 96 fromFragment( Fragment fragment, ViewModelProvider.Factory delegateFactory)97 ViewModelProvider.Factory fromFragment( 98 Fragment fragment, ViewModelProvider.Factory delegateFactory) { 99 return getHiltViewModelFactory(fragment, fragment.getArguments(), delegateFactory); 100 } 101 getHiltViewModelFactory( SavedStateRegistryOwner owner, @Nullable Bundle defaultArgs, @Nullable ViewModelProvider.Factory extensionDelegate)102 private ViewModelProvider.Factory getHiltViewModelFactory( 103 SavedStateRegistryOwner owner, 104 @Nullable Bundle defaultArgs, 105 @Nullable ViewModelProvider.Factory extensionDelegate) { 106 ViewModelProvider.Factory delegate = extensionDelegate == null 107 ? new SavedStateViewModelFactory(application, owner, defaultArgs) 108 : extensionDelegate; 109 return new HiltViewModelFactory( 110 owner, defaultArgs, keySet, delegate, viewModelComponentBuilder); 111 } 112 } 113 114 /** The activity module to declare the optional factories. */ 115 @Module 116 @InstallIn(ActivityComponent.class) 117 interface ActivityModule { 118 @Multibinds 119 @HiltViewModelMap.KeySet viewModelKeys()120 abstract Set<String> viewModelKeys(); 121 } 122 123 /** The activity entry point to retrieve the factory. */ 124 @EntryPoint 125 @InstallIn(ActivityComponent.class) 126 public interface ActivityEntryPoint { getHiltInternalFactoryFactory()127 InternalFactoryFactory getHiltInternalFactoryFactory(); 128 } 129 130 /** The fragment entry point to retrieve the factory. */ 131 @EntryPoint 132 @InstallIn(FragmentComponent.class) 133 public interface FragmentEntryPoint { getHiltInternalFactoryFactory()134 InternalFactoryFactory getHiltInternalFactoryFactory(); 135 } 136 DefaultViewModelFactories()137 private DefaultViewModelFactories() {} 138 } 139