I just started using Dagger library. I've created an AppComponent where I hold a singleton instance of my room database. I have a foreground service which needs to write something to room database when its notification button is clicked. As you know foreground service notification is always visible to user even if the user closes app and I thought if my app gets killed, the AppComponent will no longer be usable. But now I can access it and get the database instance when service notification button is clicked, even if my app has been cleared from recent apps. Here is my code:
Dagger App Module:
@Module
class AppModule {
@Provides
@Singleton
fun database(context: Context) = Room
.databaseBuilder(context, MyDatabase::class.java, "my_db.db").build()
}
Dagger App Component:
@Singleton
@Component(modules = [AppModule::class])
interface AppComponent {
@Component.Factory
interface Factory {
fun create(@BindsInstance context: Context): AppComponent
}
fun getDatabase(): MyDatabase
}
Application class:
class App : Application() {
override fun onCreate() {
super.onCreate()
appComponent = DaggerAppComponent.factory().create(applicationContext)
}
companion object {
lateinit var appComponent: AppComponent
}
}
Foreground service notification:
val intent = Intent(applicationContext, MyBroadcastReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(
applicationContext,
0,
stopIntent,
PendingIntent.FLAG_UPDATE_CURRENT
)
val notification = NotificationCompat
.Builder(applicationContext, "channel_id")
......
.addAction(0, "button text", pendingIntent)
......
.build()
BroadcastReceiver:
class MyBroadcastReceiver : BroadcastReceiver() {
@Inject
lateinit var database: MyDatabase
override fun onReceive(context: Context?, intent: Intent?) {
database = App.appComponent.getDatabase()
//Write something to database
}
}
Previous code is working perfectly even if app is completely killed. I just want to now how is it possible for me to access appComponent after app is being killed? Am I using a standard solution? Is anything wrong with my code? Is there a better way to do this?
As EpicPandaForce mentioned in comments, swiping the app away in recents only kills the task, not the application process. Your app process can be killed regardless of whether the task is destroyed. Furthermore, if you have a foreground service running, you know that the app hasn't been destroyed yet.
This isn't the only reason you can access your Room database.
Suppose you just have a notification without a foreground service. It is possible that your app will be killed in the background, and the notification will still be around. What happens if you click the button on the notification now?
As stated in the documentation for Application.onCreate()
:
Called when the application is starting, before any activity, service, or receiver objects (excluding content providers) have been created.
Implementations should be as quick as possible (for example using lazy initialization of state) since the time spent in this function directly impacts the performance of starting the first activity, service, or receiver in a process.
By the time Android instantiates your BroadcastReceiver
, the newly recreated application process has already called App.onCreate()
, so you will have access to the Room database via a new instance of AppComponent
.