【问题标题】:How to inject into a BroadcastReceiver如何注入广播接收器
【发布时间】:2015-11-30 14:59:42
【问题描述】:

是否有人已经不得不使用 dagger 将已经存在的类以及一些业务逻辑注入到 BroadcastReceiver 中?

我正在使用 dagger 1 并且已经找到了一个很好的示例 (https://github.com/adennie/fb-android-dagger),但是我找不到如何将属于不同模块的现有类添加到 BroadcastReceiver。

任何帮助或建议将不胜感激。

【问题讨论】:

    标签: android dependency-injection broadcastreceiver dagger


    【解决方案1】:

    与注入 Activity 相同

    public void onReceive(Context context, Intent intent) {
            ((Application) context.getApplicationContext()).getInjector().inject(this);
        }
    

    【讨论】:

    • 我们是否保证 Application Context 永远是一个 Application 实例?如果不是,这不是一个可以接受的答案。
    【解决方案2】:

    将对象注入广播接收器的 Dagger 2 示例。

    BroadcastReceiverModule.kt

    @Module
    abstract class BroadcastReceiverModule {
        @ContributesAndroidInjector
        abstract fun contributesMyTestReceiver() : MyTestReceiver
    }
    

    AppComponent.kt

    @Singleton
    @Component(
            modules = [
                (AndroidSupportInjectionModule::class),
                (BroadcastReceiverModule::class)
            ])
    interface AppComponent : AndroidInjector<MyApp> {
        @Component.Builder
        abstract class Builder : AndroidInjector.Builder<MyApp>()
    }
    

    应用类

    class MyApp : DaggerApplication() {
        override fun applicationInjector(): AndroidInjector<MyApp> =
                DaggerAppComponent.builder().create(this@MyApp)
    }
    

    BroadcastReceiver 类

    class MyTestReceiver : BroadcastReceiver() {
    
        @Inject
        lateinit var anInjectedObject: MyInjectObject
    
        override fun onReceive(context: Context, intent: Intent) {
            AndroidInjection.inject(this, context)
            anInjectedObject.doSomthing()
        }
    }
    

    【讨论】:

    • 这是在 2019 年执行此操作的正确方法。但是,您只需让 Application 类扩展 DaggerApplication 和 Receiver 扩展 DaggerBroadcastReceiver 即可节省最后两个步骤。
    • @s-hunter 是否也可以将BroadcastReceiverModule 定义为interface?您能否解释一下为什么为此选择abstract class?非常感谢您。
    【解决方案3】:

    现在回答这个问题可能为时已晚,但我将提供我最近项目中的一个示例,我尝试注入 AppWidgetProvider,它是 BroadcastReceiver 的直接子类。

    我们需要将改造服务注入BroadcastReceiver

    @Module
    public class NetModule {
        /** shrunk for simplicity's sake. **/
        @Singleton
        @Provides
        public WidgetService provideWidgetService(Application application, OkHttpClient client, Gson gson) {
            return new Retrofit.Builder()
                    .addConverterFactory(GsonConverterFactory.create(gson))
                    .baseUrl(application.getString(R.string.api_url))
                    .client(client)
                    .build()
                    .create(WidgetService.class);
        }
    }
    

    为带有@ContributesAndroidInjector 注释的抽象方法创建另一个抽象@Module,这些方法返回您要注入的BroadcastReceivers:

    /**
     * To inject the app widgets.
     */
    @Module
    public abstract class WidgetsModule {
        @ContributesAndroidInjector
        abstract IngredientsWidget contributesIngredientsWidget();
    }
    

    如果你忘记添加这个模块,你会得到如下错误:

    java.lang.IllegalArgumentException: No injector factory bound for 类

    然后是两个模块的组件,除了AndroidInjectionModule

    @Singleton
    @Component(modules = {AndroidInjectionModule.class, NetModule.class, WidgetsModule.class})
    public interface AppComponent {
        void inject(RecipesApp recipesApp);
    }
    

    然后在您的Application 类中实现HasBroadcastReceiverInjector 接口。

    public class RecipesApp extends Application implements HasBroadcastReceiverInjector {
    
        @Inject
        DispatchingAndroidInjector<BroadcastReceiver> broadcastReceiverInjector;
    
        @Override
        public void onCreate() {
            super.onCreate();
    
            component().inject(this);
        }
    
        public AppComponent component() {
            return DaggerAppComponent.builder()
                    .build();
        }
    
        @Override
        public AndroidInjector<BroadcastReceiver> broadcastReceiverInjector() {
            return broadcastReceiverInjector;
        }
    }
    

    最后,您可以在调用 super() 之前将 BroadcastReceiver 注入到 onReceive() 中。

    public class IngredientsWidget extends AppWidgetProvider {
    
        @Inject
        public WidgetService api;
    
    
        @Override
        public void onReceive(Context context, Intent intent) {
            /** Don't forget this line **/
            AndroidInjection.inject(this, context);
            super.onReceive(context, intent);
        }
    
    }
    

    你可以找到更多关于如何注入android组件docs

    我构建了一个小样本:broadcast-injection

    【讨论】:

    • 知道如何测试吗?
    • 这就是我喜欢的 Stackoverflow 答案:示例解释、文档链接和 GitHub 上的示例项目 - 谢谢@amrro!
    【解决方案4】:

    我设法通过定义一个提供我需要的用例的模块将用例注入到我的广播中,并且我在 onReceive 方法中添加了模块,请检查以下代码:

    我的BroadcastReceiverModule

    @Module(injects = { MyBroadcastReceiver.class }, addsTo = MyAppModule.class)
    public class BroadcastReceiverModule {
        @Provides @Singleton MyUtilsClass providesMyUtilsClass(MyUtilsClassImpl myUtilsClass) {
            return myUtilsClass;
        }
        @Provides @Singleton MyUseCase providesMyUseCase(MyUseCaseImpl myUseCaseUtils) {
            return myUseCaseUtils;
        }
    }
    

    我的BroadCastReceiver

    @Inject MyUtilsClass myUtilsClass;
    @Inject MyUseCase myUseCase;
    @Override public void onReceive(Context context, Intent intent) {
        AcidApplication.getScopedGraph(getModules().toArray()).inject(this);
        myUseCase.call();
        myUtilsClass.doSomething();
    }
    protected List<Object> getModules() {
        List<Object> result = new ArrayList<>();
        result.add(new BroadcastReceiverModule());
        return result;
    }
    

    【讨论】:

    • 注意 - 这是 Dagger 1。
    【解决方案5】:

    您可以使用 DaggerBroadcastReceiver 或覆盖 onReceive 方法,如下所示:

    public void onReceive(Context context, Intent intent) {
        AndroidInjection.inject(this, context);
        // your code should be here ...
    }
    

    匕首文件: https://dagger.dev/api/2.24/dagger/android/DaggerBroadcastReceiver

    【讨论】:

      【解决方案6】:

      只是有点晚了,但我比以前的答案略有改进,您不需要在 onReceive 方法中显式调用 AndroidInjection.inject(this, context);

      这是接收器,所以你不必这样做,诀窍是从 DaggerBroadcastReceiver 扩展:

      class MyReceiver : DaggerBroadcastReceiver() {
      
          @Inject
          lateinit var repository: MyRepository
      
          override fun onReceive(context: Context?, intent: Intent?) {
              super.onReceive(context, intent)
              // Do your stuff...
          }
      }
      

      其余的只是注册模块等。我希望它有所帮助:D

      【讨论】:

        【解决方案7】:
        • 以前的解决方案现在在最新的 Hilt 版本中不再适用,因为 Hilt 没有任何称为 AndroidInjection 的函数。
        • App Widget Provider 扩展了广播接收器。因此,您可以像这样简单地注释任何广播接收器:

        答案:

        @AndroidEntryPoint
        class StandardWidgetProvider : AppWidgetProvider() {
        
            @Inject
            lateinit var room: AppDatabase
        
            override fun onReceive(context: Context, intent: Intent?) {
                super.onReceive(context, intent)
                // do your stuff here
            }
        }
        

        【讨论】:

          【解决方案8】:

          在 KOIN 依赖注入中,

          class ServiceClass1()
          class LazyServiceClass2()
          

          //在Activity中不需要KoinComponent

          class MyActivity: AppCompatActivity() {
          
              // evaluates dependency eagerly
              val service: ServiceClass1= get()
              
              // evaluates dependency lazily
              val lazyService: LazyServiceClass2by inject()
          
              override fun onCreate(savedInstanceState: Bundle?) {
                  super.onCreate(savedInstanceState)
                       
                  // does something with services
              }
          
          }
          

          但是对于 Receiver,像下面这样扩展“KoinComponent”

          // In non-lifecycle component, KoinComponent is needed
          class SomeBroadcastReceiver: BroadcastReceiver(), KoinComponent {
              
              // evaluates dependency eagerly
              val service: Service1 = get()
              // evaluates dependency lazily
              val lazyService: LazyService2 by inject()
              
              override fun onReceive(context: Context?, intent: Intent?) {
                  // does something with services
              }
          
          }
          

          希望它对你有用。

          【讨论】:

            猜你喜欢
            • 2011-11-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多