Java + Android Jetpack + Dagger 2 在 ViewModel 中注入(inject)

标签 java android dagger-2 android-viewmodel

我刚刚学习了 dagger 2,然后我想用 android jetpack 来实现。但我有问题,无法在 ViewModel 中注入(inject)变量。

这是我的结构

  • Dagger

    --AppComponent.java

    --AppInjector.java

    --AppModule.java

    -- Injectable.java

  • 工厂

    --MainViewModelFactory.java

  • 模块

    -- FragmentBuildersModule.java

    --MainActivityModule.java

    -- ViewModelKey.java

    -- ViewModelModule.java

    -- ViewModelSubcomponent.java

  • 用户界面 -- MainFragment.java

    --MainViewModel.java

应用程序.java

MainActivity.java

我的代码MainViewModelFactory.java

@Singleton
public class MainViewModelFactory implements ViewModelProvider.Factory {
private final Map<Class<? extends ViewModel>, Provider<ViewModel>> creators;

@Inject
public MainViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> creators) {
    this.creators = creators;
}


@SuppressWarnings("unchecked")
@Override
public <T extends ViewModel> T create(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 viewmodel class " + modelClass);
    }
    try {
        return (T) creator.get();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
}

FragmentBuildersModule.java

@Module
public abstract class FragmentBuildersModule {

    @ContributesAndroidInjector
    abstract MainFragment contributeMainFragment();
}

MainActivityModule.java

@Module
public abstract class MainActivityModule {

    @ContributesAndroidInjector(modules = FragmentBuildersModule.class)
    abstract MainActivity cotributeMainActivity();
}

ViewModelKey.java

@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@MapKey
@interface ViewModelKey {
    Class<? extends ViewModel> value();
}

ViewModelModule.java

@Module
public abstract class ViewModelModule {

    @Binds
    @IntoMap
    @ViewModelKey(MainViewModel.class)
    abstract MainViewModel bindMainViewModel(MainViewModel mainViewModel);

    @Binds
    abstract ViewModelProvider.Factory bindViewModelFactory(MainViewModelFactory factory);

}

ViewModelSubComponent.java

@Subcomponent
public interface ViewModelSubcomponent {

    @Subcomponent.Builder
    interface Builder {
        ViewModelSubcomponent build();
    }

    MainViewModel mainViewModel();
}

ui.MainFragment.java

public class MainFragment extends Fragment {


    private static final String TAG = "MainFragment";

    @Inject
    ViewModelProvider.Factory viewModelFactory;

    private MainViewModel mViewModel;

    public static MainFragment newInstance() {
        return new MainFragment();
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {

        return inflater.inflate(R.layout.main_fragment, container, false);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
//        mViewModel = ViewModelProviders.of(this).get(MainViewModel.class);
        mViewModel = ViewModelProviders.of(this, viewModelFactory).get(MainViewModel.class);
        // TODO: Use the ViewModel

        TextView message = (TextView) getView().findViewById(R.id.message);

        message.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

//                String test = mViewModel.getGlobalCommon().getNama();
                GlobalCommon globalCommon = mViewModel.getGlobalCommon();
                Toast.makeText(getContext(), "tst", Toast.LENGTH_LONG).show();
            }
        });
    }

}

di.AppComponent.java

@Singleton
@Component(modules = { AndroidInjectionModule.class, AppModule.class, MainActivityModule.class})
public interface AppComponent {

    @Component.Builder
    interface Builder {
        @BindsInstance
        Builder application(Application application);
        AppComponent build();
    }

    void inject(App app);
}

di.AppInjector.java

public class AppInjector {

    private AppInjector() {}

    public static void init(App app) {
        DaggerAppComponent.builder().application(app).build().inject(app);
        app.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle bundle) {
                handleActivity(activity);
            }

            @Override
            public void onActivityStarted(Activity activity) {

            }

            @Override
            public void onActivityResumed(Activity activity) {

            }

            @Override
            public void onActivityPaused(Activity activity) {

            }

            @Override
            public void onActivityStopped(Activity activity) {

            }

            @Override
            public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {

            }

            @Override
            public void onActivityDestroyed(Activity activity) {

            }
        });
    }

    private static void handleActivity(Activity activity) {
        if(activity instanceof HasSupportFragmentInjector){
            AndroidInjection.inject(activity);
        }

        if(activity instanceof FragmentActivity){
            FragmentManager.FragmentLifecycleCallbacks fragmentCallback = new FragmentManager.FragmentLifecycleCallbacks() {
                @Override
                public void onFragmentCreated(FragmentManager fm, Fragment f,
                                              Bundle savedInstanceState) {
                    if (f instanceof Injectable) {
                        AndroidSupportInjection.inject(f);
                    }
                }
            };

            ((FragmentActivity) activity).getSupportFragmentManager()
                    .registerFragmentLifecycleCallbacks(fragmentCallback, true);
        }
    }


}

di.AppModule.java

@Module(includes = ViewModelModule.class )
public class AppModule {

    @Provides
    @Singleton
    Context provideApplication(Context application) {
        return application.getApplicationContext();
    }

    @Singleton
    @Provides
    GlobalCommon provideGlobalCommon(){
        return new GlobalCommon();
    }

}

应用程序.java

public class App extends Application implements HasActivityInjector {

    @Inject
    DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;

    @Override
    public void onCreate() {
        super.onCreate();
        if (BuildConfig.DEBUG) {
            Timber.plant(new Timber.DebugTree());
        }
        AppInjector.init(this);
    }

    @Override
    public DispatchingAndroidInjector<Activity> activityInjector() {
        return dispatchingAndroidInjector;
    }
}

MainActivity.java

public class MainActivity extends AppCompatActivity implements  HasSupportFragmentInjector {

    @Inject
    DispatchingAndroidInjector<Fragment> dispatchingAndroidInjector;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_activity);
        if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.container, MainFragment.newInstance())
                    .commitNow();
        }
    }

    @Override
    public AndroidInjector<Fragment> supportFragmentInjector() {
        return dispatchingAndroidInjector;
    }

}

我的错误:

error: [Dagger/MissingBinding] [dagger.android.AndroidInjector.inject(T)] java.util.Map<java.lang.Class<? extends android.arch.lifecycle.ViewModel>,javax.inject.Provider<android.arch.lifecycle.ViewModel>> cannot be provided without an @Provides-annotated method.
java.util.Map<java.lang.Class<? extends android.arch.lifecycle.ViewModel>,javax.inject.Provider<android.arch.lifecycle.ViewModel>> is injected at
main.main.xxx.main.main.testdagger2.factory.MainViewModelFactory.<init>(creators)
main.main.xxx.main.main.testdagger2.factory.MainViewModelFactory is injected at
main.main.xxx.main.main.testdagger2.module.ViewModelModule.bindViewModelFactory(factory)
android.arch.lifecycle.ViewModelProvider.Factory is injected at
main.main.xxx.main.main.testdagger2.ui.main.MainFragment.viewModelFactory
main.main.xxx.main.main.testdagger2.ui.main.MainFragment is injected at
dagger.android.AndroidInjector.inject(T)
component path: main.main.xxx.main.main.testdagger2.di.AppComponent → main.main.xxx.main.main.testdagger2.module.MainActivityModule_CotributeMainActivity.MainActivitySubcomponent → main.main.xxx.main.main.testdagger2.module.FragmentBuildersModule_ContributeMainFragment.MainFragmentSubcomponent

请帮助我。

最佳答案

我创建了一个演示应用程序来演示 LiveData、RxJava2、Dagger2、Paging 等的使用。由于代码太多,无法在这里发布,我将在这里发布链接。如果您认为可以更轻松或更好地提出问题。

https://github.com/mtangoo/Kasuku-Muvi

关于Java + Android Jetpack + Dagger 2 在 ViewModel 中注入(inject),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51092800/

相关文章:

java - JPA 无交易 Activity

android - Volley 库 NetworkDispatcher.run 错误

android - 从 Android Studio 运行时安装 APK 导致应用程序崩溃完美运行

java - 在房间版本 1.1.1 中创建复合主键时无法使用 Kotlin 编译器构建 android studio 项目

Android 对多个 Dagger2 模块使用单个上下文

android - 带有子组件和带有依赖组件的组件的 Dagger 2 问题

java - 如何给JDialog添加组件

java - 如何从命令行更新 Gradle 依赖项?

android - Android ScrollView 中的 VerticalScrollExtent 是什么?

java - Java套接字将byte []传输到.wav