我刚刚学习了匕首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
请帮助我。
答案 0 :(得分:1)
答案 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
})
}
}