'Fast update Android notification
I write simple audio player for Android. I wrote basic functional and now I want create notification for control audio player. I use Android classes Service and Notification and RemoteViews for big and small notifications. This work good, but, when I use fasted flipping for audio tracks my notification don't update text with name audio tracks. I create simple video for demonstration problem:
I use C# and Xamarin Forms, but it doesn't matter, since the code is very similar to Java. My service:
[Service]
public class PlayerService : Service, IPlayerService
{
private const string ACTION_SHOW_PLAYER = "music.player.ACTION.SHOW_PLAYER";
private const string ACTION_PLAY_PAUSE = "music.player.ACTION.PLAY_PAUSE";
private const string ACTION_PLAY_PREW = "music.player.ACTION.PLAY_PREW";
private const string ACTION_PLAY_NEXT = "music.player.ACTION.PLAY_NEXT";
private const string ACTION_STOP_SERVICE = "music.player.ACTION.STOP_SERVICE";
private const string ANDROID_CHANNEL_ID = "com.companyname.homeremotecontroller";
private const int NOTIFICATION_ID = 46;
private RemoteViews _remoteViewsBig = null;
private RemoteViews _remoteViewsSmall = null;
private NotificationManager _notificationManager = null;
private NotificationCompat.Builder _builder = null;
private static IPlayerService _instance = null;
private static bool _isActiveBackgroundService = false;
private static bool _isBeenStartBackgroundService= false;
public IPlayerService GetInstance()
{
return _instance;
}
public override IBinder OnBind(Intent intent)
{
return null;
}
public override void OnCreate()
{
base.OnCreate();
_instance = this;
MusicPlaylistModel.GetInstance().ChangeSound += () =>
{
UpdateSound(MusicPlaylistModel.GetInstance().CurrentSound.SoundName);
};
MusicPlaylistModel.GetInstance().MusicPlayer.TimeSound += (start, end) =>
{
// TODO: empty
};
MusicPlaylistModel.GetInstance().MusicPlayer.TickCurrentSound += (curr) =>
{
UpdateProgressSound(curr);
};
MusicPlaylistModel.GetInstance().PlayingStatus += (status) =>
{
UpdatePlayPauseStatus(status);
};
_notificationManager = ((NotificationManager)GetSystemService(NotificationService));
_notificationManager.CreateNotificationChannel(new NotificationChannel(ANDROID_CHANNEL_ID, "Audio player", NotificationImportance.High));
Intent notificationIntent = new Intent(MainActivity.Activity, typeof(MainActivity));
_remoteViewsSmall = GetSmallContentView();
_remoteViewsBig = GetBigContentView();
CreateBuilderNotification();
}
public override void OnDestroy()
{
base.OnDestroy();
}
public void CreateBuilderNotification()
{
_builder = new NotificationCompat.Builder(MainActivity.Activity, ANDROID_CHANNEL_ID)
.SetCategory(Notification.ExtraMediaSession)
.SetCustomBigContentView(_remoteViewsBig)
.SetCustomContentView(_remoteViewsSmall)
.SetSmallIcon(Resource.Mipmap.icon)
.SetOngoing(true)
.SetSilent(true)
.SetPriority((int)NotificationPriority.Max)
.SetVisibility(NotificationCompat.VisibilityPublic)
.SetAutoCancel(true)
.SetStyle(new NotificationCompat.DecoratedCustomViewStyle());
}
public Notification RecreateNotification()
{
return _builder.Build();
}
private RemoteViews GetBigContentView()
{
RemoteViews mContentViewBig = new RemoteViews(MainActivity.Activity.PackageName, Resource.Layout.player_notify_big);
Intent closeIntent = new Intent(MainActivity.Activity, typeof(PlayerService));
closeIntent.SetAction(ACTION_STOP_SERVICE);
PendingIntent pcloseIntent = PendingIntent.GetService(MainActivity.Activity, 0, closeIntent, 0);
Intent playPauseIntent = new Intent(MainActivity.Activity, typeof(PlayerService));
playPauseIntent.SetAction(ACTION_PLAY_PAUSE);
PendingIntent pPlayPauseIntent = PendingIntent.GetService(MainActivity.Activity, 0, playPauseIntent, 0);
Intent nextIntent = new Intent(MainActivity.Activity, typeof(PlayerService));
nextIntent.SetAction(ACTION_PLAY_NEXT);
PendingIntent pNextIntent = PendingIntent.GetService(MainActivity.Activity, 0, nextIntent, 0);
Intent prewIntent = new Intent(MainActivity.Activity, typeof(PlayerService));
prewIntent.SetAction(ACTION_PLAY_PREW);
PendingIntent pPrewIntent = PendingIntent.GetService(MainActivity.Activity, 0, prewIntent, 0);
mContentViewBig.SetOnClickPendingIntent(Resource.Id.btnWidgetPlayPauseMusicBig, pPlayPauseIntent);
mContentViewBig.SetOnClickPendingIntent(Resource.Id.btnWidgetCloseService, pcloseIntent);
mContentViewBig.SetOnClickPendingIntent(Resource.Id.playNextBig, pNextIntent);
mContentViewBig.SetOnClickPendingIntent(Resource.Id.playPrevBig, pPrewIntent);
return mContentViewBig;
}
private RemoteViews GetSmallContentView()
{
RemoteViews mContentViewSmall = new RemoteViews(MainActivity.Activity.PackageName, Resource.Layout.player_notify_small);
Intent closeIntent = new Intent(MainActivity.Activity, typeof(PlayerService));
closeIntent.SetAction(ACTION_STOP_SERVICE);
PendingIntent pcloseIntent = PendingIntent.GetService(MainActivity.Activity, 0, closeIntent, 0);
Intent playPauseIntent = new Intent(MainActivity.Activity, typeof(PlayerService));
playPauseIntent.SetAction(ACTION_PLAY_PAUSE);
PendingIntent pPlayPauseIntent = PendingIntent.GetService(MainActivity.Activity, 0, playPauseIntent, 0);
Intent nextIntent = new Intent(MainActivity.Activity, typeof(PlayerService));
nextIntent.SetAction(ACTION_PLAY_NEXT);
PendingIntent pNextIntent = PendingIntent.GetService(MainActivity.Activity, 0, nextIntent, 0);
Intent prewIntent = new Intent(MainActivity.Activity, typeof(PlayerService));
prewIntent.SetAction(ACTION_PLAY_PREW);
PendingIntent pPrewIntent = PendingIntent.GetService(MainActivity.Activity, 0, prewIntent, 0);
mContentViewSmall.SetOnClickPendingIntent(Resource.Id.btnWidgetCloseServiceSmall, pcloseIntent);
mContentViewSmall.SetOnClickPendingIntent(Resource.Id.btnWidgetPlayPauseMusic, pPlayPauseIntent);
mContentViewSmall.SetOnClickPendingIntent(Resource.Id.btnWidgetPlayNext, pNextIntent);
mContentViewSmall.SetOnClickPendingIntent(Resource.Id.btnWidgetPlayPrevious, pPrewIntent);
return mContentViewSmall;
}
public void RedrawNotification()
{
if(!_isActiveBackgroundService)
{
return;
}
var notification = RecreateNotification();
notification.Flags = NotificationFlags.NoClear | NotificationFlags.OngoingEvent;
_notificationManager.Notify(NOTIFICATION_ID, notification);
StartForeground(NOTIFICATION_ID, notification);
}
public void Start()
{
MainActivity.Activity.StartForegroundService(new Intent(MainActivity.Activity, typeof(PlayerService)));
_isActiveBackgroundService = true;
_isBeenStartBackgroundService = true;
}
public void Stop()
{
MainActivity.Activity.StopService(new Intent(MainActivity.Activity, typeof(PlayerService)));
_isActiveBackgroundService = false;
}
public void UpdateSound(string snd_name)
{
_remoteViewsSmall.SetTextViewText(Resource.Id.lblWidgetCurrentMusicName, snd_name);
_remoteViewsBig.SetTextViewText(Resource.Id.lblWidgetCurrentMusicName, snd_name);
_builder.SetCustomBigContentView(_remoteViewsBig)
.SetCustomContentView(_remoteViewsSmall);
RedrawNotification();
}
public void UpdateProgressSound(int currProgress)
{
// TODO: empty
}
public void UpdatePlayPauseStatus(bool status)
{
if(status)
{
_remoteViewsSmall.SetImageViewResource(Resource.Id.btnWidgetPlayPauseMusic, Resource.Drawable.play_off);
_remoteViewsBig.SetImageViewResource(Resource.Id.btnWidgetPlayPauseMusicBig, Resource.Drawable.play_off);
}
else
{
_remoteViewsSmall.SetImageViewResource(Resource.Id.btnWidgetPlayPauseMusic, Resource.Drawable.pause_off);
_remoteViewsBig.SetImageViewResource(Resource.Id.btnWidgetPlayPauseMusicBig, Resource.Drawable.pause_off);
}
_builder.SetCustomBigContentView(_remoteViewsBig)
.SetCustomContentView(_remoteViewsSmall);
RedrawNotification();
}
public override StartCommandResult OnStartCommand(Intent? intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
if (_isBeenStartBackgroundService)
{
UpdateSound(MusicPlaylistModel.GetInstance().CurrentSound.SoundName);
UpdatePlayPauseStatus(false);
RedrawNotification();
_isBeenStartBackgroundService = false;
}
string action = intent.Action;
if (action != null)
{
if (action == ACTION_STOP_SERVICE)
{
Stop();
}
else
{
new Task(async () =>
{
if (action == ACTION_PLAY_PAUSE)
{
await MusicPlaylistModel.GetInstance().Play();
return;
}
else if (action == ACTION_PLAY_PREW)
{
await MusicPlaylistModel.GetInstance().Prew();
return;
}
else if (action == ACTION_PLAY_NEXT)
{
await MusicPlaylistModel.GetInstance().Next();
return;
}
}).Start();
}
}
return StartCommandResult.Sticky;
}
}
To show the notification, the external code calls the Start
method, and to hide the notification, the external code calls the Stop
method.
I check for debugging. Application successful will hit in method UpdateSound
, where snd_name
- is correct. But text in Notification is not correct.
How fix it?
Solution 1:[1]
In UpdateSound()
you call RedrawNotification()
In RedrawNotification()
you call RecreateNotification()
In RecreateNotification()
you call _builder.Build()
But you never made any changes in _builder
.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | David Wasser |