我一直在遵循在Android应用程序中设置DI的指南,据我所知,我已经正确设置了所有设置。但是,出现以下错误:
java.lang.RuntimeException: Cannot create an instance of class com.topper.topper.ui.viewmodel.ProfileViewModel
以下是我的课程的简化版本(为简洁起见):
activityModule
@Module
public abstract class activityModule {
@ContributesAndroidInjector(modules = FragmentModule.class)
abstract Mainactivity contributeMainactivity();
}
FragmentModule
@Module
public abstract class FragmentModule {
@ContributesAndroidInjector
abstract ProfileFragment contributeProfileFragment();
}
ViewModelModule
@Module
public abstract class ViewModelModule {
@Binds
@IntoMap
@ViewModelKey(ProfileViewModel.class)
abstract ViewModel bindProfileViewModel(ProfileViewModel profileViewModel);
@Binds
abstract ViewModelProvider.Factory bindViewModelFactory(ViewModelFactory factory);
}
AppModule
@Module(includes = ViewModelModule.class)
public class AppModule {
@Provides
@Singleton
TopperDB provideDatabase(Application application) {
return Room.databaseBuilder(application,TopperDB.class,"TopperDB.db")
.build();
}
@Provides
@Singleton
CachedImageDao provideCachedImageDao(TopperDB database) {
return database.cachedImageDao();
}
@Provides
@Singleton
Executor provideExecutor() {
return Executors.newSingleThreadExecutor();
}
@Provides
@Singleton
CachedImageRepository provideCachedImageRepository(CachedImageDao cachedImageDao,Executor executor) {
return new CachedImageRepository(cachedImageDao,executor);
}
}
AppComponent
@Singleton
@Component(modules = {AndroidSupportInjectionmodule.class,AndroidInjectionmodule.class,activityModule.class,FragmentModule.class,AppModule.class})
public interface AppComponent {
void inject(TopperApp app);
@Component.Builder
interface Builder {
@BindsInstance
Builder application(Application application);
AppComponent build();
}
}
ViewModelKey
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@MapKey
public @interface ViewModelKey {
Class<? extends ViewModel> value();
}
ViewModelFactory
@Singleton
public class ViewModelFactory implements ViewModelProvider.Factory {
private final Map<Class<? extends ViewModel>,Provider<ViewModel>> creators;
@Inject
ViewModelFactory(Map<Class<? extends ViewModel>,Provider<ViewModel>> creators) {
this.creators = creators;
}
@NotNull
@SuppressWarnings("unchecked")
@Override
public <T extends ViewModel> T create(@NotNull Class<T> modelClass) {
Provider<? extends ViewModel> creator = creators.get(modelClass);
if (creator == null) {
for (Map.Entry<Class<? extends ViewModel>,Provider<ViewModel>> entry : creators.entryset()) {
if (modelClass.isAssignableFrom(entry.getKey())) {
creator = entry.getvalue();
break;
}
}
}
if (creator == null) {
throw new IllegalArgumentException("unknown model class " + modelClass);
}
try {
return (T) creator.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
CachedImageRepository
@Singleton
public class CachedImageRepository extends BaseRepository {
private final CachedImageDao cachedImageDao;
private final Executor executor;
@Inject
public CachedImageRepository(CachedImageDao cachedImageDao,Executor executor) {
this.cachedImageDao = cachedImageDao;
this.executor = executor;
}
}
ProfileViewModel
public class ProfileViewModel extends ViewModel {
private CachedImageRepository cachedImageRepo;
@Inject
public ProfileViewModel(CachedImageRepository cachedImageRepo) {
this.cachedImageRepo = cachedImageRepo;
}
}
ProfileFragment
public class ProfileFragment extends BaseFragment {
@Inject
ViewModelProvider.Factory viewModelFactory;
private ProfileViewModel mViewModel;
@Override
public void onactivityCreated(@Nullable Bundle savedInstanceState) {
super.onactivityCreated(savedInstanceState);
configureDagger();
}
public View onCreateView(@NonNull LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState) {
FragmentProfileBinding binding = DataBindingUtil.inflate(inflater,R.layout.fragment_profile,container,false);
mViewModel = ViewModelProviders.of(this.requireactivity(),viewModelFactory).get(ProfileViewModel.class);
mViewModel.init();
binding.setProfileViewModel(mViewModel);
return binding.getRoot();
}
private void configureDagger() {
AndroidSupportInjection.inject(this);
}
}
Mainactivity
public class Mainactivity extends AppCompatactivity implements ProgressDisplay,HasSupportFragmentInjector {
@Inject
DispatchingAndroidInjector<Fragment> dispatchingAndroidInjector;
@Inject
ViewModelProvider.Factory viewModelFactory;
private AppBarLayout appBarLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.configureDagger();
}
private void configureDagger() {
AndroidInjection.inject(this);
}
}
TopperApp
public class TopperApp extends Application implements HasactivityInjector {
public Context ctx;
@Inject
DispatchingAndroidInjector<activity> dispatchingAndroidInjector;
@Override
public void onCreate() {
super.onCreate();
this.initDagger();
ctx = getapplicationContext();
}
public Context getappContext() {
return ctx;
}
@Override
public DispatchingAndroidInjector<activity> activityInjector() {
return dispatchingAndroidInjector;
}
我想我已经包括了以上所有相关细节,但是如果我错过了任何事情,请告诉我。
任何帮助将不胜感激,我已经将头撞在墙上几天了。
谢谢。
编辑:如果有帮助,我尝试向 ProfileViewModel 中添加一个空构造函数,这将导致以下错误:
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.topper.topper.data.repo.CachedImageRepository.cacheImage(android.content.Context,java.lang.String,int)' on a null object reference
因此,匕首似乎没有注入到ProfileViewModel的构造函数中。