来自服务内部的 sendBroadcast,它使用协程进行网络调用
sendBroadcast from inside Service which uses Coroutine for network call
我有一个 JobIntentService,它应该进行 API 调用并在结果可用后进行广播。
我正在使用协程通过 Retrofit 进行网络调用。
但是,如果我在 CoroutineScope 中执行 sendBroadcast ,它不会触发 BroadcastReceiver
这是我的服务代码 -
MyService.kt
class MyService : JobIntentService() {
private val TAG = MyService::class.java.simpleName
private var databaseHelper: DatabaseHelper = DatabaseHelper(this)
private var imageFetcher: ImageFetcher = ImageFetcher(this)
private var imageSaver: ImageSaver = ImageSaver(this)
private val receiver = ServiceBroadcastReceiver()
override fun onHandleWork(intent: Intent) {
val filter = IntentFilter()
filter.addAction("ACTION_FINISHED_SERVICE")
registerReceiver(receiver, filter)
when (intent.action) {
"ACTION_FETCH_FROM_API" -> {
handleFetchFromAPI()
}
}
}
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(receiver)
}
private fun handleFetchFromAPI() {
val API = ServiceBuilder.buildWebService(WebService::class.java)
CoroutineScope(IO).launch {
try {
var apiSuccess : Boolean = false
val apiResponse = API.getImageOfTheDay()
if (apiResponse.isSuccessful) {
apiSuccess = true
val imageAPIResponse = apiResponse.body()
val bitmap = imageFetcher.getImageBitmapFromURL(imageAPIResponse.url)
val filePath = imageSaver.saveBitmapToFile(bitmap, "image.jpg")
withContext(Main) {
databaseHelper.saveImageInRoom(imageAPIResponse, filePath)
}
}
if(apiSuccess){
val broadCastIntent = Intent()
broadCastIntent.action = "ACTION_FINISHED_SERVICE"
sendBroadcast(broadCastIntent)
}
} catch (exception: Exception) {
Log.d(TAG, "Exception occurred ${exception.message}")
}
}
}
companion object {
private const val JOB_ID = 2
@JvmStatic
fun enqueueWork(context: Context, intent: Intent) {
enqueueWork(context, MyService::class.java, JOB_ID, intent)
}
}
}
ServiceBroadcastReceiver.kt
class ServiceBroadcastReceiver : BroadcastReceiver() {
private val TAG = ServiceBroadcastReceiver::class.java.simpleName
private lateinit var _mNotificationManager: NotificationManager
private val _notificationId = 0
private val _primaryChannelId = "primary_notification_channel"
override fun onReceive(context: Context, intent: Intent) {
_mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
when (intent.action) {
"ACTION_FINISHED_SERVICE" -> {
deliverNotification(context)
}
}
}
private fun deliverNotification(context: Context) {
val contentIntent = Intent(context, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(context,_notificationId,contentIntent,
PendingIntent.FLAG_UPDATE_CURRENT)
val builder = NotificationCompat.Builder(context,_primaryChannelId)
builder.setSmallIcon(R.mipmap.ic_launcher)
builder.setContentTitle("Hi There")
builder.setContentText("Service finished its job")
builder.setContentIntent(pendingIntent)
builder.priority = NotificationCompat.PRIORITY_HIGH
builder.setAutoCancel(true)
builder.setDefaults(NotificationCompat.DEFAULT_ALL)
_mNotificationManager.notify(_notificationId,builder.build())
}
}
getImageOfTheDay() 是 WebService.kt
中的一个挂起函数
@Headers("Content-Type: application/json")
@GET("/v1/getImageOfTheDay")
suspend fun getImageOfTheDay(): Response<ImageAPIResponse>
如果我将代码移到协程范围之外,广播就会正确发送。
我该如何解决这个问题?
你不应该在这里使用协程。 onHandleWork
方法在后台线程上调用,从该方法返回表示工作已完成并且可以终止服务。
当您启动与 launch
的协程时,onHandleWork
returns 立即终止,您的服务将终止。
您应该直接调用您的网络 API 而不是在协程中,因为 JobIntentService
已经设计为以这种方式工作。
我有一个 JobIntentService,它应该进行 API 调用并在结果可用后进行广播。
我正在使用协程通过 Retrofit 进行网络调用。 但是,如果我在 CoroutineScope 中执行 sendBroadcast ,它不会触发 BroadcastReceiver
这是我的服务代码 -
MyService.kt
class MyService : JobIntentService() {
private val TAG = MyService::class.java.simpleName
private var databaseHelper: DatabaseHelper = DatabaseHelper(this)
private var imageFetcher: ImageFetcher = ImageFetcher(this)
private var imageSaver: ImageSaver = ImageSaver(this)
private val receiver = ServiceBroadcastReceiver()
override fun onHandleWork(intent: Intent) {
val filter = IntentFilter()
filter.addAction("ACTION_FINISHED_SERVICE")
registerReceiver(receiver, filter)
when (intent.action) {
"ACTION_FETCH_FROM_API" -> {
handleFetchFromAPI()
}
}
}
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(receiver)
}
private fun handleFetchFromAPI() {
val API = ServiceBuilder.buildWebService(WebService::class.java)
CoroutineScope(IO).launch {
try {
var apiSuccess : Boolean = false
val apiResponse = API.getImageOfTheDay()
if (apiResponse.isSuccessful) {
apiSuccess = true
val imageAPIResponse = apiResponse.body()
val bitmap = imageFetcher.getImageBitmapFromURL(imageAPIResponse.url)
val filePath = imageSaver.saveBitmapToFile(bitmap, "image.jpg")
withContext(Main) {
databaseHelper.saveImageInRoom(imageAPIResponse, filePath)
}
}
if(apiSuccess){
val broadCastIntent = Intent()
broadCastIntent.action = "ACTION_FINISHED_SERVICE"
sendBroadcast(broadCastIntent)
}
} catch (exception: Exception) {
Log.d(TAG, "Exception occurred ${exception.message}")
}
}
}
companion object {
private const val JOB_ID = 2
@JvmStatic
fun enqueueWork(context: Context, intent: Intent) {
enqueueWork(context, MyService::class.java, JOB_ID, intent)
}
}
}
ServiceBroadcastReceiver.kt class ServiceBroadcastReceiver : BroadcastReceiver() {
private val TAG = ServiceBroadcastReceiver::class.java.simpleName
private lateinit var _mNotificationManager: NotificationManager
private val _notificationId = 0
private val _primaryChannelId = "primary_notification_channel"
override fun onReceive(context: Context, intent: Intent) {
_mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
when (intent.action) {
"ACTION_FINISHED_SERVICE" -> {
deliverNotification(context)
}
}
}
private fun deliverNotification(context: Context) {
val contentIntent = Intent(context, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(context,_notificationId,contentIntent,
PendingIntent.FLAG_UPDATE_CURRENT)
val builder = NotificationCompat.Builder(context,_primaryChannelId)
builder.setSmallIcon(R.mipmap.ic_launcher)
builder.setContentTitle("Hi There")
builder.setContentText("Service finished its job")
builder.setContentIntent(pendingIntent)
builder.priority = NotificationCompat.PRIORITY_HIGH
builder.setAutoCancel(true)
builder.setDefaults(NotificationCompat.DEFAULT_ALL)
_mNotificationManager.notify(_notificationId,builder.build())
}
}
getImageOfTheDay() 是 WebService.kt
中的一个挂起函数@Headers("Content-Type: application/json")
@GET("/v1/getImageOfTheDay")
suspend fun getImageOfTheDay(): Response<ImageAPIResponse>
如果我将代码移到协程范围之外,广播就会正确发送。 我该如何解决这个问题?
你不应该在这里使用协程。 onHandleWork
方法在后台线程上调用,从该方法返回表示工作已完成并且可以终止服务。
当您启动与 launch
的协程时,onHandleWork
returns 立即终止,您的服务将终止。
您应该直接调用您的网络 API 而不是在协程中,因为 JobIntentService
已经设计为以这种方式工作。