Java + Android Jetpack + Dagger 2插入ViewModel

时间:2018-06-29 00:35:17

标签: java android dagger-2 android-viewmodel

我刚刚学习了匕首2,然后我想用android jetpack实现。但是我有问题,无法在ViewModel中注入variabel。

这是我的结构

  • 匕首

    -AppComponent.java

    -AppInjector.java

    -AppModule.java

    -Injectable.java

  • 工厂

    -MainViewModelFactory.java

  • 模块

    -FragmentBuildersModule.java

    -MainActivityModule.java

    -ViewModelKey.java

    -ViewModelModule.java

    -ViewModelSubcomponent.java

  • ui -MainFragment.java

    -MainViewModel.java

App.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();
    }

}

App.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;
    }

}

myerror:

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

请帮助我。

2 个答案:

答案 0 :(得分:1)

我创建了一个演示应用程序,以演示LiveData,RxJava2,Dagger2,分页等等的用法。由于太多的代码无法在此处发布,因此我将在此处发布链接。如果您认为可以简化或更好地解决问题,那么

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

答案 1 :(得分:0)

我写了一个库,应该使它更简单:https://github.com/radutopor/ViewModelFactory

@ViewModelFactory
class SampleViewModel(@Provided private val repository: Repository, private val userId: Int) : ViewModel() {
    private val greeting = MutableLiveData<String>()

    init {
        val user = repository.getUser(userId)
        greeting.value = "Hello, $user.name"
    }

    fun getGreeting() = greeting as LiveData<String>
}

在视图中:

class SampleActivity : AppCompatActivity() {
    @Inject
    lateinit var sampleViewModelFactory2: SampleViewModelFactory2

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_sample)
        appComponent.inject(this)

        val userId = intent.getIntExtra("USER_ID", -1)
        val viewModel = ViewModelProviders.of(this, sampleViewModelFactory2.create(userId))
            .get(SampleViewModel::class.java)

        viewModel.getGreeting().observe(this, Observer { greeting ->
            greetingTextView.text = greeting
        })
    }
}