Search code examples
androidfirebasekotlinfirebase-cloud-messagingdagger-2

How to provide database to MyFirebaseMessagingService using Dagger 2 so that I can store fcm message locally in android


How can I make it possible to pass database Instance to the MyFirebaseMessagingService class which extends FirebaseMessagingService so that I can save data payload locally?

Note: I already setup dagger 2 in my app, it's working perfectly.

Below is MyFirebaseMessagingService class:

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

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

And below is the AppModule class of Dagger 2

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

Is it possible to provide database and dao to MyFirebaseMessagingService class?

I tried above method to provide exampleOneDao to the MyFirebaseMessagingService class, but it throws the following Exception

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

Thank You.


Solution

  • Finally got the solution from this link: https://github.com/googlesamples/android-architecture-components/issues/253

    As MyFirebaseMessagingService is a Service class, so for injection in Service class, Dagger provides a way through which we can inject dependencies into Service class. Below are the steps to enable injection in service class:

    1) Make Application implements HasServiceInjector and inject a DispatchingAndroidInjector for services.

    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) Create a new module to perform injection over your services.

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

    3) Register your new module in your application's component.

    @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) And finally, override method onCreate of the service adding AndroidInjection.inject(this).

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