Jorn
Jorn

Reputation: 272

How to inject the creation of a BroadcastReceiver object in Fragment using Dagger2?

I need to inject the creation of NetReceiver object into my Fragment but I get the following error:

error: [Dagger/MissingBinding] com.example.myapp.NetReceiver.OnNetCallback cannot be provided without an @Provides-annotated method.

Let me show you what I have tried. This is my NetReceiver class:

public class NetReceiver extends BroadcastReceiver {
    private OnNetCallback onNetCallback;

    @Inject
    public NetReceiver(OnNetCallback onNetCallback) {
        this.onNetCallback = onNetCallback;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        if (someCondition) {
            onNetCallback.enableOperation(true);
        }
    }

    public interface OnNetCallback {
        void enableOperation(boolean isOk);
    }
}

As you can see, I want to inject in the constructor a NetCallback object. I have also created a Module class that looks like this:

@Module
public abstract class NetReceiverModule {
    @ContributesAndroidInjector //Error?!?!?!?!
    abstract NetReceiver.OnNetCallback provideOnNetCallback();

    @Singleton
    @Provides
    static NetReceiver provideNetReceiver(NetReceiver.OnNetCallback onNetCallback) {
        return new NetReceiver(onNetCallback);
    }
}

This is how my fragment look liked when it worked:

public class MapFragment extends Fragment implements NetReceiver.OnNetCallback {
    private NetReceiver netReceiver;

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        //Inflate View
        netReceiver = new NetReceiver(this); //Worked
    }

    @Override
    public void onResume() {
    super.onResume();
        mainActivity.registerReceiver(netReceiver, intentFilter);
    }

    @Override
    public void onPause() {
    super.onPause();
        mainActivity.unregisterReceiver(netReceiver);
    }
}

And this is how it looks when it is not working:

public class MapFragment extends DaggerFragment implements NetReceiver.OnNetCallback {
    @Inject NetReceiver netReceiver;

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        //Inflate View
        //netReceiver = new NetReceiver(this); //Worked
    }

    @Override
    public void onResume() {
    super.onResume();
        mainActivity.registerReceiver(netReceiver, intentFilter);
    }

    @Override
    public void onPause() {
    super.onPause();
        mainActivity.unregisterReceiver(netReceiver);
    }
}

Upvotes: 1

Views: 2723

Answers (1)

Pavlo Ostasha
Pavlo Ostasha

Reputation: 16729

The problem is that Dagger2 cannot do magic. How it should know from where to provide a OnNetCallback. Your fragment extends this callback but neither its constructor is annotated with @Inject annotation(because you are not advised to create explicit fragment constructors) nor it is provided with @Provides annotated method in your module, nor OnNetCallback is bind with MapFragment via @Bind annotated method which is a "must be" when you trying to inject interface like this along with a @Qualifier.

But that is not the main issue.

Even if you will manage to do all the previous stuff correctly it will still not work because there will be a circular dependency - MapFragment depends on NetReceiver, NetReceiver depends on OnNetCallback, OnNetCallback is a MapFragment, thus NetReceiver depends on MapFragment. Dagger won't let you do it.

If you want your MapFragment to implement OnNetCallback I would suggest something like:

public class NetReceiver extends BroadcastReceiver {

    public OnNetCallback onNetCallback;

    @Override
    public void onReceive(Context context, Intent intent) {
        if (someCondition && onNetCallback!= null) {
            onNetCallback.enableOperation(true);
        }
    }

    public interface OnNetCallback {
        void enableOperation(boolean isOk);
    }
}


public class MapFragment extends DaggerFragment implements NetReceiver.OnNetCallback {

    @Inject NetReceiver netReceiver;

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        //Inflate View
        netReceiver.onNetCallback = this
    }

    @Override
    public void onResume() {
    super.onResume();
        mainActivity.registerReceiver(netReceiver, intentFilter);
    }

    @Override
    public void onPause() {
    super.onPause();
        mainActivity.unregisterReceiver(netReceiver);
    }
}

If you want it to be injected - create some separate from Fragment implementation of OnNetCallback and @Provide it in module and inject it into fragment.

Also @ContributesAndroidInjector should be used for the injeters but not for the injectees - it tells Dagger that this class should be injected with some stuff described with @Inject, @Provides and @Bind annotations.

Also I would recommend you to read an official guide regarding Dagger2 and its usage for Android.

Hope it helps.

Upvotes: 1

Related Questions