7

我正在使用以下 google 示例项目:https ://github.com/googlesamples/android-architecture-components作为我的新项目的参考,并且在尝试向项目添加第二个活动时遇到困难。

这是我在编译时遇到的错误

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

这是我的代码

活动模块

@Module
public abstract class ActivityModule {

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

    @ContributesAndroidInjector(modules = FragmentBuildersModule.class)
    abstract ContactActivity contributeContactActivity();
} 

应用组件

@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);
}

应用程序注入器

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);
        }
    }
}

应用模块

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

FragmentBuilders 模块

@Module
public abstract class FragmentBuildersModule {

    @ContributesAndroidInjector
    abstract AddContactsFragment contributeAddUserFragment();

    @ContributesAndroidInjector
    abstract ContactsFragment contributeContactsFragment();

    @ContributesAndroidInjector
    abstract ChalkboardFragment contributeChalkboardFragment();
}

可注射的

public interface Injectable {
}

视图模型键

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

视图模型模块

@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;
    }
}

导航控制器

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);
    }
}

联系活动

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;
    }
}
4

1 回答 1

22

“组件中存在具有匹配键的绑定”意味着您已在整个对象图中的某个位置绑定了一个依赖项,但无法从需要注入它的子组件访问它。这是javadoc:

实用程序代码在绑定图中的所有子组件中查找与键匹配的绑定,以便在当前子图中未找到绑定时告知用户该绑定存在于其他位置。如果与键匹配的绑定存在于子组件或兄弟组件中,这通常是用户实际想要使用的。

绑定在同级组件中的位置图

例如,假设您有两个活动,即 ActivityA 和 ActivityB。您使用ActivityA 模块而不是 ActivityB 模块生成子组件@ContributesAndroidInjector并在其中绑定。如果您在 ActivityB 中Foo请求注入,您将收到该错误消息。Foo@Inject Foo foo

在您的特定情况下,您遇到的错误可以通过以下方式重现:

  1. 从 GitHub 克隆项目

    git clone https://github.com/googlesamples/android-architecture-components.git`
    
  2. 复制粘贴MainActivity到新文件中ContactsActivity

  3. 修改MainActivityModule看起来像你的ActivityModule

所以从这里我们可以得出结论,你ActivityModule是有问题的。这@ContributesAndroidInjector并不像看起来那么简单。这实际上意味着您正在为您在此处指定的 Activity 创建一个新的 Dagger 2 子组件(请参阅此处的文档)。

子组件可以使用来自父组件的绑定,但不能使用兄弟组件。ContributesAndroidInjector您在ActivityModule创建两个兄弟子组件中的两行 for :一个 forMainActivity和一个 for ContactsActivity

但是,NavigationController取决于子组件MainActivity的对象图中的绑定,MainActivity而不是子组件的绑定ContactsActivityAddContactsFragment已成为ContactsActivity子组件对象图的一部分,无法MainActivity再访问。这意味着当 Dagger 2 试图注入NavigationController你的内部AddContactsFragment时,它不能MainActivity作为它的依赖项提供。这解释了错误消息的“无法提供”部分。

尽管它不能MainActivity在那个特定的对象图中提供,但通常AndroidInjector 确实知道MainActivity错误消息“存在绑定键”。这是什么绑定键?绑定MainActivity.classMainActivityFactory. 这个键绑定在哪里?在ActivityModule你写@ContributesAndroidInjectorfor的时候MainActivity

如何解决这个问题超出了 StackOverflow 问题的范围,因为它涉及对代码的冗长重构。您将需要重新组织对象图,以便NavigationController不再依赖于MainActivity. 也许你可以让它依赖,AppCompatActivity因为它是你的两个活动的超类。然后,您需要停止使用ContributesAndroidInjector并为您的两个活动编写显式模块,其中包括AppCompatActivity.

但是,现在请回到基础并从更简单的事情开始。在没有完全理解的情况下从一个复杂的项目开始,然后只是修改它,希望它能起作用,这是灾难的根源。

Codepath Dagger 2 教程项目更容易理解,并将让您熟悉 Dagger 2 中涉及的基本概念。一旦您熟悉了基本概念并理解了依赖组件和子组件,那么您可以尝试更困难的例子。祝你好运!

于 2017-08-25T09:57:56.813 回答