Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

error: [Dagger/MissingBinding] [dagger.android.AndroidInjector.inject(T)] Dagger

I wanna to make a simple project with one main activity and multiple fragments. here I have two fragments at one activity and I want to inject presenter to login fragment but it doesn't work. where is my mistake?

MainApplication.java

public class MainApplication extends DaggerApplication{


private static ApplicationComponent component;
@Override
public void onCreate() {
    super.onCreate();
    Utils.init(this);
}
public static ApplicationComponent getComponent() {
    return component;
}


protected AndroidInjector<? extends DaggerApplication> applicationInjector() 
{
    component = 
    DaggerApplicationComponent.builder().application(this).build();
    component.inject(this);
    return component;
  }


}

MainActivity.java

public class MainActivity extends DaggerAppCompatActivity  {



private Fragment[] mFragments = new Fragment[2];
private int curIndex;

@Inject
HomeFragment homeFragment;

@Inject
LoginFragment loginFragment;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    if (savedInstanceState != null) {
        curIndex = savedInstanceState.getInt("curIndex");
    }
    mFragments[AppConstant.HOME_FRAGMENT] = homeFragment;
    mFragments[AppConstant.LOGIN_FRAGMENT] = loginFragment;

    FragmentUtils.add(getSupportFragmentManager(), mFragments, 
  R.id.container, curIndex);
    showCurrentFragment(AppConstant.LOGIN_FRAGMENT);
}
private void showCurrentFragment(int index) {
    FragmentUtils.showHide(curIndex = index, mFragments);
}

@Override
public void onSaveInstanceState(Bundle outState, PersistableBundle 
  outPersistentState) {
    super.onSaveInstanceState(outState, outPersistentState);
    outState.putInt("curIndex", curIndex);
  }


 }

ApplicationComponent.java

@Singleton
@Component(modules = {
    ContextModule.class,
    ApiServiceModule.class,
    AndroidSupportInjectionModule.class,
    ActivityBuilder.class
 })
  public interface ApplicationComponent extends 
         AndroidInjector<DaggerApplication> {

void inject(MainApplication component);

@Component.Builder
interface Builder {

    ApplicationComponent build();

    @BindsInstance
    Builder application(MainApplication application);
}
}

LoginFragment.java

public class LoginFragment extends DaggerFragment{

View mRootView;


@Inject
HomeFragment homeFragment;


@Inject
LoginContract.Presenter mPresenter;

@Inject
public LoginFragment() {
    // Required empty public constructor
}


@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    mRootView =inflater.inflate(R.layout.fragment_login, container, false);
    ButterKnife.bind(this,mRootView);
    // Inflate the layout for this fragment
    return mRootView;
}

@OnClick(R.id.button)
public void goToHome(){
    FragmentUtils.replace(this,homeFragment,false);

}

@Override
public void onAttach(Context context) {
    super.onAttach(context);

}

@Override
public void onDetach() {
    super.onDetach();

     }


  }

ActivityBuilder.java

@Module
public abstract class ActivityBuilder {

@ContributesAndroidInjector(modules = {MainActivityModule.class , 
FragmentContainerModule.class, AndroidSupportInjectionModule.class} )
abstract MainActivity bindMainActivity();


 }

FragmentContainerModule.java

@Module
public abstract class FragmentContainerModule {


 @ContributesAndroidInjector(modules = 
             {HomeFragmentModule.class,
              AndroidSupportInjectionModule.class})
abstract HomeFragment contributeHomeFragmentInjector();


@FragmentScope
@ContributesAndroidInjector(modules = 
           {LoginFragmentModule.class,
             AndroidSupportInjectionModule.class})
abstract LoginFragment contributeLoginFragmentInjector();




}

** LoginFragmentModule.java

@Module
public abstract class LoginFragmentModule {

@FragmentScope
@Binds
public abstract LoginContract.Presenter presenter(LoginPresenter 
      loginPresenter);
}

and this is the error :

error: [Dagger/MissingBinding] [dagger.android.AndroidInjector.inject(T)] 
ir.heart.heartproject.utils.MvpUtils.LoginContract.Presenter cannot be 
provided without an @Provides-annotated method.
A binding with matching key exists in component: 
ir.heart.heartproject.utils.di.
modules.FragmentContainerModule_ContributeLoginFr 
agmentInjector.LoginFragmentSubcomponent
ir.heart.heartproject.utils.MvpUtils.
LoginContract.Presenter is injected at
ir.heart.heartproject.views.fragments.LoginFragment.mPresenter
ir.heart.heartproject.views.fragments.LoginFragment is injected at
ir.heart.heartproject.views.activities.MainActivity.loginFragment
ir.heart.heartproject.views.activities.MainActivity is injected at
dagger.android.AndroidInjector.inject(T)
component path: 
ir.heart.heartproject.utils.di.component.ApplicationComponent ? 
ir.heart.heartproject.utils.di.modules.
ActivityBuilder_BindMainActivity.MainActivitySubcomponent
like image 711
omid Avatar asked Aug 22 '18 10:08

omid


People also ask

What is the best way to implement dagger dependency injection in Android?

Hilt is built on top of Dagger and it provides a standard way to incorporate Dagger dependency injection into an Android application. Note: If you're already familiar with Dagger, check out these best practices.

What is the use of dagger in Android?

For more information about this, check out the Using Dagger in your Android app codelab. Dagger modules are a way to encapsulate how to provide objects in a semantic way. You can include modules in components but you can also include modules inside other modules. This is powerful, but can be easily misused.

What is the generic inject () method in a dagger interface?

A generic inject () method doesn't tell Dagger what needs to be provided. The functions in the interface can have any name, but calling them inject () when they receive the object to inject as a parameter is a convention in Dagger.

Can I inject a private field in Android blueprints dagger?

For more information about how to inject these classes, check out the code in the official Android Blueprints Dagger implementation, in the dev-dagger branch. One of the considerations with Dagger is that injected fields cannot be private.


1 Answers

You use @inject to annotate the constructor of LoginFragment, when a new instance is requested, Dagger constructs instances of your LoginFragment class and satisfies their dependencies (like the mPresenter field). Because MainActivitySubcomponent doesn’t access LoginFragmentModule, Dagger gives you an error that can not provide LoginContract.Presenter. instead of using constructor injection, if you use another approach for providing LoginFragment for MainActivity, the problem will be solved. You should remove @inject from LoginFragment constructor and create a module to provide it like the following example:

@Module
public class MainModule {

    @Provides
    public static LoginFragment provideLoginFragment() {
        return LoginFragment.newInstance("param1", "param2");
    }

}

Dagger tips: don't use Constructor injection for an object that system instantiate it. in android, for injecting dependency in activity and fragment, you should use field injection approach.

like image 164
abbas oveissi Avatar answered Sep 23 '22 15:09

abbas oveissi