如何使用 Dagger 2 向 MyFirebaseMessagingService 提供数据库,以便我可以在 android 本地存储 fcm 消息

Posted

技术标签:

【中文标题】如何使用 Dagger 2 向 MyFirebaseMessagingService 提供数据库,以便我可以在 android 本地存储 fcm 消息【英文标题】:How to provide database to MyFirebaseMessagingService using Dagger 2 so that I can store fcm message locally in android 【发布时间】:2018-12-03 16:17:47 【问题描述】:

我怎样才能将数据库实例传递给扩展FirebaseMessagingServiceMyFirebaseMessagingService 类,以便我可以在本地保存data 有效负载?

注意:我已经在我的应用中设置了 dagger 2,它运行良好。

下面是MyFirebaseMessagingService类:

class MyFirebaseMessagingService @Inject constructor(exampleOneDao: ExampleOneDao?) : FirebaseMessagingService() 

    override fun onMessageReceived(remoteMessage: RemoteMessage?) 
    //need db instance to store data payload locally (Room)
    

下面是匕首2的AppModule

@Module(includes = arrayOf(ViewModelModule::class))
class AppModule() 

    // --- DATABASE INJECTION ---
    @Provides
    @Singleton
    internal fun provideDatabase(application: Application): MyDatabase 
        return Room.databaseBuilder(application,
               MyDatabase::class.java, "MyDatabase.db")
              .build()
    

    @Provides
    @Singleton
    internal fun provideExampleOneDao(database: MyDatabase): ExampleOneDao 
        return database.exampleOneDao()
    

    @Provides
    @Singleton
    internal fun provideMyFirebaseMessagingService(exampleOneDao: 
        ExampleOneDao): MyFirebaseMessagingService 
           return MyFirebaseMessagingService(exampleOneDao)
    

是否可以为MyFirebaseMessagingService类提供数据库和dao?

我尝试上述方法将exampleOneDao 提供给MyFirebaseMessagingService 类,但它抛出了以下Exception

MyFirebaseMessagingService: java.lang.InstantiationException: java.lang.Class<com.example.user.app.firebase.messaging.MyFirebaseMessagingService> has no zero argument constructor

谢谢。

【问题讨论】:

为什么不可能?你试过了吗? 是的,我试过了,但是它抛出了实例化异常。打算用我试过但没有成功的方法更新发布的代码 ***.com/questions/37052261/… 没有。自己做。关于这个主题有很多例子可以找到 @TimCastelijns 感谢您激励我寻找解决方案,我最终得到了很好的解决方案并且学习曲线很好。 【参考方案1】:

使用 Dagger 将依赖项注入服务必须通过公共类变量,而不是来自构造函数,以避免类型错误MyFirebaseMessagingService 没有零参数构造函数。 p>

实施solution 通行证后

发件人:

class MyFirebaseMessagingService @Inject constructor(exampleOneDao: ExampleOneDao?) : FirebaseMessagingService() 

    override fun onMessageReceived(remoteMessage: RemoteMessage?) 
    //need db instance to store data payload locally (Room)
    

收件人:

class MyFirebaseMessagingService : FirebaseMessagingService() 

@Inject 
private lateinit var exampleOneDao: ExampleOneDao? 

    override fun onMessageReceived(remoteMessage: RemoteMessage?) 
    //need db instance to store data payload locally (Room)
    

GL

Source

【讨论】:

【参考方案2】:

这是 Kotlin 的实现:

Application.kt

@Inject
lateinit var dispatchingServiceInjector: DispatchingandroidInjector<Service>

override fun serviceInjector(): AndroidInjector<Service> 
    return dispatchingServiceInjector

模块.kt

@Module
abstract class FirebaseServiceModule 
    @ContributesAndroidInjector
    abstract fun contributeMyFirebaseMessengingService(): MyFirebaseMessengingService

组件.kt

@Component(modules = [FirebaseServiceModule::class])
interface Component 
    ...

MyFirebaseMessengingService.kt

override fun onCreate() 
    AndroidInjection.inject(this);
    super.onCreate()

【讨论】:

【参考方案3】:

终于从这个链接得到了解决方案:https://github.com/googlesamples/android-architecture-components/issues/253

由于MyFirebaseMessagingServiceService 类,所以对于Service 类中的注入,Dagger 提供了一种将依赖项注入到Service 类中的方法。以下是在服务类中启用注入的步骤:

1) 使应用程序实现 HasServiceInjector 并为服务注入 DispatchingAndroidInjector。

public class App extends Application implements HasActivityInjector, HasServiceInjector 

    @Inject
    DispatchingAndroidInjector<Activity> dispatchingActivityInjector;

    // Add this line
    @Inject
    DispatchingAndroidInjector<Service> dispatchingServiceInjector;

    @Override
    public void onCreate() 
        super.onCreate();
        AppInjector.init(this);
    

    @Override
    public AndroidInjector<Activity> activityInjector() 
        return dispatchingActivityInjector;
    

    // override this method after implementing HasServiceInjector
    @Override
    public AndroidInjector<Service> serviceInjector() 
        return dispatchingServiceInjector;
    


2) 创建一个新模块以对您的服务执行注入。

@Module
abstract class ServiceBuilderModule 

    // for my case, the service class which needs injection is MyFirebaseMessagingService
    @ContributesAndroidInjector
    abstract MyFirebaseMessagingService contributeMyFirebaseMessagingService();


3) 在应用程序组件中注册新模块。

@Component(modules = 
        AndroidSupportInjectionModule.class,
        AppModule.class,
        ActivityBuilderModule.class,
        // Need to define previously created module class here
        ServiceBuilderModule.class
)
@Singleton
public interface AppComponent 
    @Component.Builder
    interface Builder 
        @BindsInstance
        Builder application(App application);
        AppComponent build();
    
    void inject(App app);

4) 最后,覆盖添加 AndroidInjection.inject(this) 的服务的 onCreate 方法。

public class MyFirebaseMessagingService extends FirebaseMessagingService 

    //So now we are able to inject here same as we do in Activity. No need for constructor injection
    @Inject ExampleOneDao exampleOneDao

    // Override this method first
    @Override
    public void onCreate() 
        AndroidInjection.inject(this);
        super.onCreate();
    

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) 
        // use your dao here to store remoteMessage data payload into your database, e.g exampleOneDao.save(somethingHere)
    



【讨论】:

它在 Kotlin 中不起作用,它会触发错误 No injector factory bound for Class。注入器工厂绑定到 com.fuentesoft.messagingapp.service.MessageService 的超类型:[com.google.firebase.messaging.FirebaseMessagingService]。你的意思是为子类型绑定一个注入器工厂吗? @MijaelViricochea 这是因为你需要设置一个注入器工厂,即你需要告诉注入器这个服务类是注入目标之一。您可以通过创建一个新的模块类来做到这一点,例如:``` @Module abstract class ServiceModule @ContributesAndroidInjector(modules = []) internal abstract fun bindService(): MessageService ``` 并确保在声明时包含 ServiceModule组件。然后这个错误就会消失。

以上是关于如何使用 Dagger 2 向 MyFirebaseMessagingService 提供数据库,以便我可以在 android 本地存储 fcm 消息的主要内容,如果未能解决你的问题,请参考以下文章

如何在仍然使用 Dagger2 的同时解决循环依赖?

Dagger 2 Activity 上下文/ApplicationContext 模块

Dagger 2 注入 Android 应用程序上下文

Android 仪器测试中的 Dagger 2 注入

如何在Dagger 2中创建包含DAO对象的View Model?

Android依赖注入Dagger的使用和源码解析(上篇)