我想了解为什么我在这里有匕首循环依赖:
class MachineFragment : Fragment() {
@Inject
lateinit var viewModelFactory: ViewModelFactory
private lateinit var viewModel: MachinesViewModel
override fun onCreate(savedInstanceState: Bundle?) {
AndroidSupportInjection.inject(this)
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
super.onCreateView(inflater, container, savedInstanceState)
viewModel = ViewModelProvider(this, viewModelFactory).get(MachinesViewModel::class.java)
return inflater.inflate(R.layout.fragment_machines, container, false)
}
@Singleton
@Component(
dependencies = [],
modules = [
AppModule::class,
TestViewModelModule::class,
InjectorModule::class
]
)
interface AppComponent {
fun inject(subject: AppApplication)
public abstract class TestViewModelModule {
@Binds
public abstract ViewModelFactory bindViewModelFactory(ViewModelFactory viewModelFactory);
/*
you have to explicitly define ViewModel instead of concrete
implementation to avoid cycle dependency error
*/
@Binds
@IntoMap
@ViewModelKey(MachinesViewModel.class)
abstract ViewModel bindMachinesViewModel(MachinesViewModel vm);
}
public class ViewModelFactory implements ViewModelProvider.Factory {
private final Map<Class<? extends ViewModel>, Provider<ViewModel>> viewModels;
@Inject
public ViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> viewModels) {
this.viewModels = viewModels;
}
@Override
public <T extends ViewModel> T create(Class<T> modelClass) {
Provider<ViewModel> viewModelProvider = viewModels.get(modelClass);
if (viewModelProvider == null) {
throw new IllegalArgumentException("model class " + modelClass + " not found");
}
return (T) viewModelProvider.get();
}
}
但是,当我在
MainActivity
中定义相同的注入字段时,循环依赖性消失了:
class MainActivity : AppCompatActivity() {
@Inject
lateinit var viewModelFactory: ViewModelFactory
private lateinit var viewModel: MachinesViewModel
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
/* start destination in navigation.xml defines entry point */
viewModel = ViewModelProvider(this, viewModelFactory).get(MachinesViewModel::class.java)
}
我已经通过添加
@Named("machine-vm-factory")
注释解决了这个问题,但我不清楚根本原因。我会感谢您对此的想法。谢谢!
我认为问题在于
TestViewModelModule
中的这一行:
@Binds
public abstract ViewModelFactory bindViewModelFactory(ViewModelFactory viewModelFactory);
在这里,当有人请求
ViewModelFactory
时,你要求 Dagger 给你一个 ViewModelFactory
,并且由于 @Binds
的优先级高于 @Inject
,Dagger 并不真正知道如何构造 ViewModelFactory
,因此循环。
添加限定符会改变关键:
@Binds
@Named("machine-vm-factory")
public abstract ViewModelFactory bindViewModelFactory(ViewModelFactory viewModelFactory);
这意味着当有人请求
@Named("machine-vm-factory") ViewModelFactory
时,Dagger 会使用 ViewModelFactory
带注释的构造函数给我们一个 @Inject
,这样循环就消失了。