I am using a foreground service with ongoing notification which updates very frequently.
When the service launches I initialize the notification manager with the notification builder and keep all the references.
The notification has custom layout with buttons. Each time the user presses a button I update the remote views and call the notificationManager.notify(service_id, notificationBuilderCompat.build()).
Eventually after many clicks I receive TransactionTooLargeException error with the size of the data parcel in bytes. Each notify() adds more bytes to this number.
What is the best approach to deal with this?
Demo of the code used:
class MyService: LifecycleService() {
var notificationBuilderCompat: NotificationCompat.Builder
var notificationManager: NotificationManager
var viewModel: ViewModel
val FOREGROUND_SERVICE = 10
val EXTRA_NOTIFICATION_TYPE = "EXTRA_NOTIFICATION_TYPE"
val NOTIFICATION_CHANNEL_ID = "channel_01"
override fun onCreate() {
super.onCreate()
// View model that holds the data
viewModel = ViewModel()
registerReceiver(broadcastReceiver, IntentFilter(NOTIFICATION_MESSAGE_INTENT)
notificationManager = getSytemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// In case of android O
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
val channel = NotificationChannel(NOTIFICATION_CHANNEL_ID, "notification_name", NotificationManager.IMPORTNACE_MAX)
notificationManager.createNotificationChannel(channel)
}
notificationBuilderCompat = NotificationCompat.Builder(applicationContext, NOTIFICATION_CHANNEL_ID)
}
ovveride fun onStartCommand(intent: Intent?, flags: Int, startId:Int): Int {
// Received start notification command
if (intent.action == START_FOREGROUND_ACTION) {
setupNotification()
viewModel.observerData.observe(this, Observer { data ->
remoteViews.setTextViewText(R.id.notification_text, data)
// This handles the update with the new data, and also where the exception happens
notificationManager.notify(FOREGROUND_SERVICE, notificationBuilderCompat.build())
})
} else {
stopForground(true)
unregisterReceiver(broadcastReceiver)
stopSelf()
}
}
fun setupNotification() {
remoteViews = RemoteViews(packageName, R.layout.item_notification)
// Setting all the remote views here
remoteViews.setImageViewResource(R.id.notification_app_icon, R.mipmap.ic_luancher)
// Setting the click event
val clickIntent = Intent(NOTIFICATION_MESSAGE_INTENT)
clickIntent.putExtra(EXTRA_NOTIFICATION_TYPE, 1)
val clickPendingIntent = PendingIntent.getBroadcast(this, 1, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT)
remoteVies.setOnClickPendingIntent(R.id.notification_button, clickPendingIntent)
notificationBuilderCompat.setContent(remoteViews)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setTicker("Notificaion on")
.setCustomBigContentView(remoteViews)
.setSmallIcon(R.drawable.icon)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setOngoing(true)
.setOnlyAlertOnce(true)
.setDefaults(0)
startForeground(FORGROUND_SERVICE, notificationBuilderCompat.build()
}
// This is the broadcast receiver class to handle the click on the notification button
val broadcastReceiver = object: BroadcastReceiver() {
ovveride fun onReceive(context: Context?, intent: Intent?) {
// Getting the notification type
val notificationType = intent!!.getIntExtra(EXTRA_NOTIFICATION_TYPE, 0)
if (notificationType == 1) {
// Updating the data here which invokes the observer
viewModel.updateData()
}
}
}
}