I'm trying to create a simple dagger 2 application while using support v4 fragments. After I modified my application I got this strange compilation error
Error:(35, 8) error: [dagger.android.AndroidInjector.inject(T)] java.util.Map<java.lang.Class<? extends android.support.v4.app.Fragment>,javax.inject.Provider<dagger.android.AndroidInjector.Factory<? extends android.support.v4.app.Fragment>>> cannot be provided without an @Provides-annotated method.
java.util.Map<java.lang.Class<? extends android.support.v4.app.Fragment>,javax.inject.Provider<dagger.android.AndroidInjector.Factory<? extends android.support.v4.app.Fragment>>> is injected at
dagger.android.DispatchingAndroidInjector.<init>(injectorFactories)
dagger.android.DispatchingAndroidInjector<android.support.v4.app.Fragment> is injected at
app.series.com.tvshowsapplication.ui.main.MainActivity.fragmentDispatchingAndroidInjector
app.series.com.tvshowsapplication.ui.main.MainActivity is injected at
dagger.android.AndroidInjector.inject(arg0)
After a quick search I found this link. It says I would need to use
The thing is I didn't understand where should I need to put this part
@Multibinds
abstract Map<Class<? extends android.app.Fragment>, AndroidInjector.Factory<? extends android.app.Fragment>> bindNativeFragments();
My guess I need to put it in BaseActivity because it's an abstract function, but how do I implement it in the main activity?
My MainActivity:
public class MainActivity extends BaseActivity<ActivityMainBinding, MainViewModel> implements MainNavigator, HasSupportFragmentInjector {
@Inject
ViewModelProvider.Factory mViewModelFactory;
@Inject
DispatchingAndroidInjector<Fragment> fragmentDispatchingAndroidInjector;
private MainViewModel mMainViewModel;
private DrawerLayout mDrawer;
private Toolbar mToolbar;
private NavigationView mNavigationView;
// private SwipePlaceHolderView mCardsContainerView;
ActivityMainBinding mActivityMainBinding;
public static Intent getStartIntent(Context context) {
Intent intent = new Intent(context, MainActivity.class);
return intent;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mActivityMainBinding = getViewDataBinding();
mMainViewModel.setNavigator(this);
setUp();
}
@Override
protected void onResume() {
super.onResume();
if (mDrawer != null)
mDrawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
}
public void onFragmentDetached(String tag) {
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment fragment = fragmentManager.findFragmentByTag(tag);
if (fragment != null) {
fragmentManager
.beginTransaction()
.disallowAddToBackStack()
.setCustomAnimations(R.anim.slide_left, R.anim.slide_right)
.remove(fragment)
.commitNow();
unlockDrawer();
}
}
private void setUp() {
mDrawer = mActivityMainBinding.drawerView;
mToolbar = mActivityMainBinding.toolbar;
mNavigationView = mActivityMainBinding.navigationView;
// mCardsContainerViewerView = mActivityMainBinding.cardsContainer;
setSupportActionBar(mToolbar);
ActionBarDrawerToggle mDrawerToggle = new ActionBarDrawerToggle(
this,
mDrawer,
mToolbar,
R.string.open_drawer,
R.string.close_drawer) {
@Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
hideKeyboard();
}
@Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
}
};
mDrawer.addDrawerListener(mDrawerToggle);
mDrawerToggle.syncState();
setupNavMenu();
String version = getString(R.string.version) + " " + BuildConfig.VERSION_NAME;
mMainViewModel.updateAppVersion(version);
mMainViewModel.onNavMenuCreated();
// setupCardContainerView();
subscribeToLiveData();
}
private void subscribeToLiveData() {
}
private void setupNavMenu() {
NavHeaderMainBinding navHeaderMainBinding = DataBindingUtil.inflate(getLayoutInflater(),
R.layout.nav_header_main, mActivityMainBinding.navigationView, false);
mActivityMainBinding.navigationView.addHeaderView(navHeaderMainBinding.getRoot());
navHeaderMainBinding.setViewModel(mMainViewModel);
mNavigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
mDrawer.closeDrawer(GravityCompat.START);
switch (item.getItemId()) {
// case R.id.navItemAbout:
// showAboutFragment();
// return true;
// case R.id.navItemRateUs:
// RateUsDialog.newInstance().show(getSupportFragmentManager());
// return true;
// case R.id.navItemFeed:
// startActivity(FeedActivity.getStartIntent(MainActivity.this));
// return true;
// case R.id.navItemLogout:
// mMainViewModel.logout();
// return true;
// default:
// return false;
}
return false;
}
});
}
// private void showAboutFragment() {
// lockDrawer();
// getSupportFragmentManager()
// .beginTransaction()
// .disallowAddToBackStack()
// .setCustomAnimations(R.anim.slide_left, R.anim.slide_right)
// .add(R.id.clRootView, AboutFragment.newInstance(), AboutFragment.TAG)
// .commit();
// }
private void lockDrawer() {
if (mDrawer != null)
mDrawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
}
private void unlockDrawer() {
if (mDrawer != null)
mDrawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
}
@Override
public void openLoginActivity() {
startActivity(LoginActivity.getStartIntent(this));
finish();
}
@Override
public void handleError(Throwable throwable) {
// handle error
}
@Override
public MainViewModel getViewModel() {
mMainViewModel = ViewModelProviders.of(this, mViewModelFactory).get(MainViewModel.class);
return mMainViewModel;
}
@Override
public int getBindingVariable() {
return BR.viewModel;
}
@Override
public int getLayoutId() {
return R.layout.activity_main;
}
@Override
public AndroidInjector<Fragment> supportFragmentInjector() {
return fragmentDispatchingAndroidInjector;
}
}
UPDATE
I actually added the module in the component class, here is my AppComponent
@Singleton
@Component(modules = {AndroidInjectionModule.class, AppModule.class, ActivityBuilder.class})
public interface AppComponent {
@Component.Builder
interface Builder {
@BindsInstance
Builder application(Application application);
AppComponent build();
}
void inject(TVShowsApp app);
}
AppModule
@Module
public class AppModule {
@Provides
@Singleton
Context provideContext(Application application) {
return application;
}
@Provides
@Singleton
CalligraphyConfig provideCalligraphyDefaultConfig() {
return new CalligraphyConfig.Builder()
.setDefaultFontPath("fonts/source-sans-pro/SourceSansPro-Regular.ttf")
.setFontAttrId(R.attr.fontPath)
.build();
}
}
and ActivityBuilder
@Module
public abstract class ActivityBuilder {
@ContributesAndroidInjector(modules = MainActivityModule.class)
abstract MainActivity bindMainActivity();
}
You need to put it in a module that you then register in your Component, but you don't have to declare it manually, as Dagger already has the AndroidInjectionModule
(or AndroidSupportInjectionModule
with AppCompat) which you can use.
You can find more about the Android setup in the official documentation or see some additional information in a similar question about when you need to install the module that was asked quite recently.
You're not showing your AppComponent, but you most likely just forgot to add the module, so you can fix your error by adding it to your component.
// add it somehow like this
@Component(modules = { AndroidSupportInjectionModule.class, AppModule.class })
public interface AppComponent {
void inject(App app);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With