【问题标题】:How to inject the creation of a BroadcastReceiver object in Fragment using Dagger2?如何使用 Dagger2 在 Fragment 中注入 BroadcastReceiver 对象的创建?
【发布时间】:2019-11-07 11:03:34
【问题描述】:

我需要将 NetReceiver 对象的创建注入我的 Fragment 但我收到以下错误:

错误:[Dagger/MissingBinding] com.example.myapp.NetReceiver.OnNetCallback 不能在没有 @Provides 注释的方法的情况下提供。

让我向您展示我的尝试。这是我的NetReceiver 班级:

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

如您所见,我想在构造函数中注入一个NetCallback 对象。我还创建了一个如下所示的 Module 类:

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

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

这是我的片段在工作时的样子:

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

这就是它不工作时的样子:

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

【问题讨论】:

  • OnNetCallback 是一个接口,通过定义abstract NetReceiver.OnNetCallback provideOnNetCallback(); dagger 不知道要返回哪个实现。你想做的是@Binds abstract fun bindOnNetCallback(callback: MapFragment): OnNetCallback。但我不会这样设计,所以我必须在广播接收器中注入片段。也许你可以有一个交互器/存储库/本地数据源作为MapFragment 和NetReceiver 之间的连接
  • @sonnet 您能否提供一个答案,以便我更好地查看代码?谢谢

标签: android dependency-injection broadcastreceiver dagger-2 dagger


【解决方案1】:

问题是Dagger2 不能变魔术。它应该如何知道从哪里提供OnNetCallback。您的片段扩展了此回调,但其构造函数既没有使用@Inject 注释进行注释(因为不建议您创建显式片段构造函数),也没有在您的模块中提供@Provides 注释方法,也没有OnNetCallback 与@ 绑定987654328@ 通过@Bind 带注释的方法,当您尝试将这样的接口与@Qualifier 一起注入时,这是“必须的”。

但这不是主要问题。

即使你能正确地完成前面所有的事情,它仍然无法工作,因为会有一个循环依赖 - MapFragment 依赖于 NetReceiver,NetReceiver 依赖于 OnNetCallback,OnNetCallback 是一个MapFragment,因此NetReceiver 依赖于MapFragment。 Dagger 不会让你这么做的。

如果您希望您的 MapFragment 实现 OnNetCallback,我建议您这样做:

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

如果您希望它被注入 - 创建一些独立于 Fragment 实现的 OnNetCallback 和 @Provide 在模块中并将其注入到片段中。

@ContributesAndroidInjector 也应该用于喷射器,但不能用于被注射者——它告诉Dagger 这个类应该注入一些用@Inject、@Provides 和@Bind 注释描述的东西。

我还建议您阅读有关Dagger2 和its usage for Android 的official guide。

希望对你有帮助。

【讨论】:

  • via @Bind annotated method which is a "must be" when you trying to inject interface 这不是“必须”。您可以使用@Provides 提供不同的接口实现
  • 感谢您抽出宝贵时间回答我的问题。据我了解,我所要做的就是在NetReceiver 中公开onNetCallback 字段,删除构造函数并使用netReceiver.onNetCallback = this,但是我应该将这两种方法都保留在我的NetReceiverModule 类中吗?还是一个人?还是没有?
  • 你可以留下两个,但第一个应该看起来像@ContributesAndroidInjector abstract fun injectMapFragment(): MapFragment
  • @PaulOst 我认为这对我来说太复杂了。我会尝试做更多尝试来解决这个问题,如果是这样,我会接受你的回答。为您的想法投票。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-13
  • 1970-01-01
  • 2022-01-15
  • 2019-06-28
  • 2018-08-10
  • 1970-01-01
相关资源
最近更新 更多