Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 388
Sharoon Amjid Avatar asked Jun 25 '18 06:06

Sharoon Amjid


People also ask

How do I send a FCM data message?

For sending FCM notification payload you can use Firebase Cloud Messaging Tool in firebase console. And click on Send your first message. Then enter the Title and body field. If you wish to send it to a particular device then click on Send test message and enter the FCM registration token.

How can I get FCM registration token in Android?

On initial startup of your app, the FCM SDK generates a registration token for the client app instance. If you want to target single devices or create device groups, you'll need to access this token by extending FirebaseMessagingService and overriding onNewToken .

How do I use firebase cloud messaging on Android?

Sending Notifications using Firebase Cloud Messaging UI Step 1, Go to the Firebase console. Under Engage, go to Cloud Messaging. We can use this tool to send out notifications to a specific group, device, or topic. Click on “Send your first message” and enter a title and text for the notification.


2 Answers

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


}
like image 198
Sharoon Amjid Avatar answered Sep 19 '22 06:09

Sharoon Amjid


Here is the Kotlin implementation:

Application.kt

@Inject
lateinit var dispatchingServiceInjector: DispatchingAndroidInjector<Service>

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

Module.kt

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

Component.kt

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

MyFirebaseMessengingService.kt

override fun onCreate() {
    AndroidInjection.inject(this);
    super.onCreate()
}
like image 44
sonique Avatar answered Sep 20 '22 06:09

sonique