Zookey
Zookey

Reputation: 2707

How to inject presenter into Fragment with Dagger2?

I have RegisterPresenterImpl that I want to inject into fragment. My app crash when I am calling method register() of that presenter.It says that my presenter is null.

How I can solve this?

public class RegisterAccountFragment extends Fragment implements RegisterAccountView {


@Inject
RegisterAccountPresenterImpl registerPresenter;

public RegisterAccountFragment() {
    // Required empty public constructor
}


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View v =  inflater.inflate(R.layout.fragment_register_account, container, false);

 DaggerRegisterAccountComponent.builder()
            .netComponent(((App) getActivity().getApplicationContext()).getNetComponent())
            .registerAccountModule(new RegisterAccountModule(this))
            .build()
            .inject(this);

   registerPresenter.register(getName(), getEmail(), getPassword(), getConfirm());
     } 
}

Component interface:

 @FragmentScoped
 @Component(dependencies = NetComponent.class, modules =  RegisterAccountModule.class)
  public interface RegisterAccountComponent {
       void inject(RegisterAccountFragment fragment);
}

Here is module class:

@Module
public class RegisterAccountModule {

private RegisterAccountView view;

public RegisterAccountModule(RegisterAccountView view){
    this.view = view;
}


@Provides
@FragmentScoped
RegisterAccountView providesRegisterAccountView(){
    return view;
   }
}

Here is class called RegisterPresenterImpl

 public class RegisterAccountPresenterImpl implements RegisterAccountPresenter{

private RegisterAccountView view;
private Retrofit retrofit;
private CompositeDisposable compositeDisposable = new CompositeDisposable();

@Inject
public RegisterAccountPresenterImpl(Retrofit retrofit, RegisterAccountView view){
    this.retrofit = retrofit;
    this.view = view;
}

@Override
public void register(String name, String email, String password, String confirm) {
    // CODE
    }
}

Upvotes: 1

Views: 2345

Answers (2)

EpicPandaForce
EpicPandaForce

Reputation: 81529

Should be

public class RegisterAccountFragment extends Fragment implements RegisterAccountView {       
    @Inject
    RegisterAccountPresenter registerPresenter; // <-- not impl, why use DI then?

And

@FragmentScoped // <-- scope here
public class RegisterAccountPresenterImpl implements RegisterAccountPresenter{

    private final RegisterAccountView view;
    private final Retrofit retrofit;

    @Inject
    public RegisterAccountPresenterImpl(Retrofit retrofit, RegisterAccountView view){
        this.retrofit = retrofit;
        this.view = view;
    }
}

And

@Module
public class RegisterAccountModule {

    private RegisterAccountView view;

    public RegisterAccountModule(RegisterAccountView view){
        this.view = view;
    }

    @Provides
    // @FragmentScoped // <-- no need for scoping item in module
    RegisterAccountView providesRegisterAccountView(){
        return view;
    }

    @Provides // <-- provide constructor injected stuff and bind to interface
    RegisterAccountPresenter registerAccountPresenter(RegisterAccountPresenterImpl impl) {
        return impl;
    }
}

Upvotes: 2

phatnhse
phatnhse

Reputation: 3920

Provide your RegisterAccountPresenterImpl in RegisterAccountComponent

It should be like this:

@FragmentScoped
@Component(dependencies = NetComponent.class, modules =  
RegisterAccountModule.class)
public interface RegisterAccountComponent {
   void inject(RegisterAccountFragment fragment);

   RegisterAccountPresenterImpl getRegisterAccountPresenterImlp();
}

There is something about your implementation

  1. Inject Constructor/Field/Method is not support public yet. Remove that redundant keyword
  2. Init your DaggerRegisterAccountComponent in onCreate() instead of onCreateView() to make sure it will be built before using any dependency.
  3. Consider using final for all field in RegisterAccountPresenterImpl which is set inside constructor. Because it will initialize one time only.
private final RegisterAccountView view;

private final Retrofit retrofit;
  1. I just don't understand why you have to define a view (which is your fragment) inside a presenter and vice versa. Is this a circular dependency?

I found this tutorial is the super cool post about using MVP and Dagger. Please consider to read it

One more thing: If you want to debug Dagger-2 effectively, go to your Dagger...Component class to see what was built in there. Android Studio will help you find any issues when using it.

Hope this help!

Upvotes: 3

Related Questions