This one will require a bit of context, please bare with me...
I have migrated a dependency for evaluating NFC data to a new application. Whenever an NFC tag is discovered, my application will spawn an Activity to handle the event. In the onCreate function of this NfcActivity, a background service (let's call it MyNfcHelperService) is started to retrieve some data on the scanned tag:
class NfcActivity : AppCompatActivity() {
/*...*/
override fun onCreate(savedInstanceState: Bundle?) {
/*...*/
val intent = Intent(this, MyNfcHelperService::class.java)
.putExtra(/*...*/)
startService(intent)
}
}
The work produced by this service is later retrieved and used by the NfcActivity. It all used to work just fine, but once released into the wild we noticed some crashes, which would report Not allowed to start service Intent on the startService(intent) call.
I quickly came across this related post, suggesting this is due to some improvements in RAM management on background processes (introduced in Android 8).
Following the accepted answer and comments raised, I studied the docs on JobIntentServices and ended up with a similar setup. I would've liked to drop the MyNfcHelperService all together and move its logic into the MyJobIntentService. But what happens inside MyNfcHelperService is an absolute black-box to me. Thus, I wrapped the aforementioned service inside the onHandleWork of my derived JobIntentService like so:
class MyJobIntentService: JobIntentService() {
companion object {
private const val JOB_ID = 1000
fun start(context: Context) {
val intentPkm = Intent(context, MyNfcHelperService::class.java)
.putExtra(/*...*/)
enqueueWork(context, intentPkm)
}
private fun enqueueWork(context: Context, intent: Intent) {
enqueueWork(context, MyJobIntentService::class.java, JOB_ID, intent)
}
}
override fun onHandleWork(intent: Intent) {
applicationContext.startService(intent)
}
}
Then I applied this class in NfcActivity:
class NfcActivity : AppCompatActivity() {
/*...*/
override fun onCreate(savedInstanceState: Bundle?) {
/*...*/
MyJobIntentService.start(applicationContext)
}
}
Thus far, the code seems to work. But I am hesitant to release it into the wild, because it feels a bit hacky and I am unsure if this solution actually solved the aforementioned issue. After all, I understand that this infrastructure creates a background service from a scheduled job.
So, is my code robust towards the java.lang.IllegalStateException: Not allowed to start service Intent error, or did I totally head the wrong way? If the latter is the case, can anyone suggest an alternate approach, taking into account that I cannot access the guts of MyNfcHelperService?
After @MD's comment, I changed my approach towards using WorkManager. This should be most robust against different API versions. I followed the official docs and arrived at the following worker setup:
Then I adjusted the code inside
NfcActivitylike so:Initial tests have worked just fine. My understanding of why this fixes the
java.lang.IllegalStateException: Not allowed to start service Intentissue would be that android will now schedule a work request which meets the requirements of launchingMyNfcHelperServiceonly when my app is allowed to create background processes.That said, I still have a bit of a headache using a worker to start a service. Feels really redundant to do so and I am unsure of any additional implications this may lead. Thus, I wont accept this as an answer just now.
I'd really appreciate any additional comments and/or answers on the matter!