这是编译时遇到的错误
Error:(22,8) error: [dagger.android.AndroidInjector.inject(T)] com.apps.myapp.ui.common.MainActivity cannot be provided without an @Inject constructor or from an @Provides-annotated method. This type supports members injection but cannot be implicitly provided. com.apps.myapp.ui.common.MainActivity is injected at com.apps.myapp.ui.common.NavigationController.<init>(mainActivity) com.apps.myapp.ui.common.NavigationController is injected at com.apps.myapp.ui.addContacts.AddContactsFragment.navigationController com.apps.myapp.ui.addContacts.AddContactsFragment is injected at dagger.android.AndroidInjector.inject(arg0) A binding with matching key exists in component: com.apps.myapp.di.ActivityModule_ContributeMainActivity.MainActivitySubcomponent
这是我的代码
ActivityModule
@Module public abstract class ActivityModule { @ContributesAndroidInjector(modules = FragmentBuildersModule.class) abstract MainActivity contributeMainActivity(); @ContributesAndroidInjector(modules = FragmentBuildersModule.class) abstract ContactActivity contributeContactActivity(); }
AppComponent
@Singleton @Component(modules = { AndroidInjectionModule.class,AppModule.class,ActivityModule.class}) public interface AppComponent { @Component.Builder interface Builder { @BindsInstance Builder application(Application application); AppComponent build(); } void inject(App app); }
AppInjector
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 savedInstanceState) { 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 outState) { } @Override public void onActivityDestroyed(Activity activity) { } }); } private static void handleActivity(Activity activity) { if (activity instanceof HasSupportFragmentInjector) { AndroidInjection.inject(activity); } if (activity instanceof FragmentActivity) { ((FragmentActivity) activity).getSupportFragmentManager() .registerFragmentLifecycleCallbacks( new FragmentManager.FragmentLifecycleCallbacks() { @Override public void onFragmentCreated(FragmentManager fm,Fragment f,Bundle savedInstanceState) { if (f instanceof Injectable) { AndroidSupportInjection.inject(f); } } },true); } } }
的AppModule
@Module(includes = viewmodelModule.class) class AppModule { @Singleton @Provides BnderAPIService provideService() { return new Retrofit.Builder() .baseUrl("serverurl") .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(new LiveDataCallAdapterFactory()) .build() .create(APIService.class); } @Singleton @Provides Db provideDb(Application app) { return Room.databaseBuilder(app,Db.class,"Db.db").build(); } @Singleton @Provides UserDao provideUserDao(Db db) { return db.userDao(); } @Singleton @Provides ContactDao provideContactDao(Db db) { return db.contactDao(); } }
FragmentBuildersModule
@Module public abstract class FragmentBuildersModule { @ContributesAndroidInjector abstract AddContactsFragment contributeAddUserFragment(); @ContributesAndroidInjector abstract ContactsFragment contributeContactsFragment(); @ContributesAndroidInjector abstract ChalkboardFragment contributeChalkboardFragment(); }
注射
public interface Injectable { }
viewmodelKey
@Documented @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @MapKey @interface viewmodelKey { Class<? extends viewmodel> value(); }
viewmodelModule
@Module abstract class viewmodelModule { @Binds @IntoMap @viewmodelKey(AddContactsviewmodel.class) abstract viewmodel bindAddContactsviewmodel(AddContactsviewmodel addContactsviewmodel); @Binds @IntoMap @viewmodelKey(Contactsviewmodel.class) abstract viewmodel bindContactsviewmodel(Contactsviewmodel contactsviewmodel); @Binds @IntoMap @viewmodelKey(Chalkboardviewmodel.class) abstract viewmodel bindChalkboardviewmodel(Chalkboardviewmodel chalkboardviewmodel); @Binds abstract viewmodelProvider.Factory bindviewmodelFactory(viewmodelFactory factory); }
应用
public class App extends Application implements HasActivityInjector { @Inject DispatchingAndroidInjector<Activity> dispatchingAndroidInjector; @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); MultiDex.install(this); } @Override public void onCreate() { super.onCreate(); if (BuildConfig.DEBUG) { } AppInjector.init(this); } @Override public DispatchingAndroidInjector<Activity> activityInjector() { return dispatchingAndroidInjector; } }
NavigationController
public class NavigationController { private final int containerId; private final FragmentManager fragmentManager; @Inject public NavigationController(MainActivity mainActivity) { this.containerId = R.id.container; this.fragmentManager = mainActivity.getSupportFragmentManager(); } public void navigateToUsers() { Log.i("TAG","Navigate to users"); String tag = "users"; AddContactsFragment userFragment = AddContactsFragment.create(); fragmentManager.beginTransaction() .replace(containerId,userFragment,tag) .addToBackStack(null) .commitAllowingStateLoss(); } public void navigateToContacts() { Log.i("TAG","Navigate to contacts"); String tag = "contacts"; ContactsFragment contactsFragment = ContactsFragment.create(); fragmentManager.beginTransaction() .add(contactsFragment,tag) .addToBackStack(null) .commitAllowingStateLoss(); } public void navigatetochalkboard() { Log.i("TAG","Navigate to chalkboard"); String tag = "chalkboard"; ChalkboardFragment chalkboardFragment = ChalkboardFragment.create(); fragmentManager.beginTransaction() .add(chalkboardFragment,tag) .addToBackStack(null) .commitAllowingStateLoss(); } }
主要活动
public class MainActivity extends AppCompatActivity implements LifecycleRegistryOwner,HasSupportFragmentInjector { private final LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this); @Inject DispatchingAndroidInjector<Fragment> dispatchingAndroidInjector; @Inject NavigationController navigationController; private Toolbar toolbar; @Override public LifecycleRegistry getLifecycle() { return lifecycleRegistry; } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityMainBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_main); binding.setHandler(this); binding.setManager(getSupportFragmentManager()); toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); } @Override public DispatchingAndroidInjector<Fragment> supportFragmentInjector() { return dispatchingAndroidInjector; } static class ViewPagerAdapter extends FragmentPagerAdapter { private final List<Fragment> mFragmentList = new ArrayList<>(); private final List<String> mFragmentTitleList = new ArrayList<>(); public ViewPagerAdapter(FragmentManager manager) { super(manager); } @Override public Fragment getItem(int position) { return mFragmentList.get(position); } @Override public int getCount() { return mFragmentList.size(); } public void addFragment(Fragment fragment,String title) { mFragmentList.add(fragment); mFragmentTitleList.add(title); } @Override public CharSequence getPageTitle(int position) { return mFragmentTitleList.get(position); } } @BindingAdapter({"handler"}) public static void bindViewPagerAdapter(final ViewPager view,final MainActivity activity) { final ViewPagerAdapter adapter = new ViewPagerAdapter(activity.getSupportFragmentManager()); adapter.addFragment(new ChalkboardFragment(),"Chalkboard"); adapter.addFragment(new ContactsFragment(),"Contacts"); view.setAdapter(adapter); } @BindingAdapter({"pager"}) public static void bindViewPagerTabs(final TabLayout view,final ViewPager pagerView) { view.setupWithViewPager(pagerView,true); } }
ContactActivity
public class ContactActivity extends AppCompatActivity implements LifecycleRegistryOwner,HasSupportFragmentInjector { private final LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this); @Inject DispatchingAndroidInjector<Fragment> dispatchingAndroidInjector; @Override public LifecycleRegistry getLifecycle() { return lifecycleRegistry; } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_contact); if (savedInstanceState == null) { } } @Override public DispatchingAndroidInjector<Fragment> supportFragmentInjector() { return dispatchingAndroidInjector; } }
解决方法
Utility code that looks for bindings matching a key in all subcomponents in a binding graph so that a user is advised that a binding exists elsewhere when it is not found in the current subgraph. If a binding matching a key exists in a sub- or sibling component,that is often what the user actually wants to use.
例如,假设您有两个活动,ActivityA和ActivityB.使用@ContributesAndroidInjector生成子组件并在ActivityA模块中绑定Foo,但不绑定ActivityB模块.如果您使用@Inject Foo foo请求ActivityB中的Foo注入,您将收到该错误消息.
在您的特定情况下,您获得的错误可以通过以下方式重现:
>从GitHub克隆项目
git clone https://github.com/googlesamples/android-architecture-components.git`
>将MainActivity复制粘贴到新文件ContactsActivity中
>将MainActivityModule修改为与ActivityModule类似
因此,我们可以得出结论,您的ActivityModule存在问题. @ContributesAndroidInjector并不像看起来那么简单.它实际上意味着您要为在此处指定的活动创建新的Dagger 2子组件(请参阅docs here).
子组件可以使用父组件的绑定,但不能使用兄弟组件. ActivityModule中的两行ContributesAndroidInjector创建了两个兄弟子组件:一个用于MainActivity,另一个用于ContactsActivity.
但是,NavigationController依赖于MainActivity,MainActivity绑定在MainActivity子组件的对象图中,但不包含在ContactsActivity子组件的对象图中. AddContactsFragment已成为ContactsActivity子组件的对象图的一部分,并且不再具有对MainActivity的访问权限.这意味着当Dagger 2尝试在您的AddContactsFragment中注入NavigationController时,它无法提供MainActivity作为它的依赖项.这解释了错误消息的“无法提供”部分.
虽然它无法在该特定对象图中提供MainActivity,但AndroidInjector一般都知道MainActivity,因此错误消息“存在绑定密钥”.这有什么约束力?将MainActivity.class绑定到MainActivityFactory的键.这个键的位置在哪里?在为ActiveActivity编写@ContributesAndroidInjector时的ActivityModule中.
如何解决这个问题超出了StackOverflow问题的范围,因为它涉及代码的冗长重构.您需要重新组织对象图,以便NavigationController不再依赖于MainActivity.也许你可以让它依赖于AppCompatActivity,因为它是你的两个活动的超类.然后,您需要停止使用ContributesAndroidInjector并为包含AppCompatActivity绑定的两个活动编写显式模块.
但是,现在请回到基础,并从更容易开始.这是一个灾难的秘诀,从一个复杂的项目开始,没有完全理解,只是修改它希望它可以工作.
Codepath Dagger 2 tutorial project更容易理解,让您熟悉Dagger 2中涉及的基本概念.一旦您熟悉了基本概念并理解了相关组件和子组件,那么您可以尝试更难的示例.祝好运!