I am new to android development and I try to create a background download feature for my app. I followed this http://developer.android.com/guide/topics/ui/notifiers/notifications.html#CustomExpandedView to create my custom notification.
The downloading is performed, I checked the downloaded file in the sdcard. Also,the status bar icon and title are changed properly.
The problem is that the custom layout I provide for the notification does not appear (expand under the bar). Here is the related code parts inside private AsyncTask class:
#Override
protected void onPreExecute() {
// create and configure the notification
notification = new Notification(R.drawable.download, "Downloading map..", System.currentTimeMillis());
notification.flags = notification.flags | Notification.FLAG_ONGOING_EVENT;
//create a custom layout for the notification
myContentView = new RemoteViews(appContext.getPackageName(), R.layout.download_progress);
myContentView.setImageViewResource(R.id.status_icon, R.drawable.ic_menu_save);
myContentView.setTextViewText(R.id.status_text, "download in progress");
myContentView.setProgressBar(R.id.status_progress, 100, 0, false);
notification.contentView = myContentView;
notification.contentView.apply(appContext, dl.getListView());
//instantiate the pending intent
Intent myIntent = new Intent(appContext, DownloadList.class);
myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
int requestID = (int) System.currentTimeMillis();
PendingIntent myPendingIntent = PendingIntent.getActivity(appContext, requestID, myIntent, 0);
notification.contentIntent = myPendingIntent;
//add the Notification object to the notification manager
notificationManager = (NotificationManager) appContext.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(NOTIF_ID, notification);
}
#Override
protected void onProgressUpdate(Integer... progress) {
//update progress bar
notification.contentView.setProgressBar(R.id.status_progress, 100, progress[0], false);
notificationManager.notify(NOTIF_ID, notification);
}
}
Note that my DownloadList class extends ListActivity.
Do I need to do something more that just "notification.contentView = myContentView;" in order to inflate the layout?
Hmm... Well I compared your code to my code that already works... and I don't see many differences... But, it is possible that one of these minor differences is important.
final Notification notification = new Notification(R.drawable.icon, "Downloading", System.currentTimeMillis());
notification.flags = notification.flags | Notification.FLAG_ONGOING_EVENT;
notification.contentView = new RemoteViews(getApplicationContext().getPackageName(), R.layout.download_progress);
notification.contentView.setImageViewResource(R.id.status_icon, R.drawable.ic_status);
notification.contentView.setTextViewText(R.id.status_text, "Downloading in progress");
notification.contentView.setProgressBar(R.id.status_progress, 100, progress, false);
Intent notificationIntent = new Intent(MainPage.mainActivity, MainPage.class);
PendingIntent contentIntent = PendingIntent.getActivity(MainPage.mainActivity, 0, notificationIntent, 0);
notification.contentIntent = contentIntent;
//getApplicationContext();
final NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(
Context.NOTIFICATION_SERVICE);
notificationManager.notify(NOTIFICATION_MESSAGE, notification);
First, I looked at your old code and noticed that the NOTIF_ID = 1 I'm not so sure that is a good idea because what if someone else has an ID of one. Of course I could be mistaken about that, but I just pounded in a number like 792489743 and I expect no one else would have the same number. Just a precaution I suppose.
Second, I didn't get to see if the resources were correct? What does the stack trace say? I suppose that it would've just quit out on it if there was a problem there though.
Third, I put my in its own task as Service kinda as follows
public class DownloadService extends IntentService {
//initializing code and stuff
private class DownloadTask extends AsyncTask<String, Void, Boolean> {
and I did it in the doInBackground This way if the user kills the app or what not it wouldn't kill the download.
Lastly, I've never used apply I don't personally see how it would hurt, but I haven't seen an example that uses it either.
Hope this helps some!
It was an emulator problem after all.....
It lagged when I "dragged down" the notification! I killed some CPU extensive processes on my PC resulting to a faster emulator.
Lesson learned. Leave the heavy multitasking to pros or to another PC.
Related
My application has a notification in the notifications bar that shows the battery level. The notification works but when the checkbox in the preferences is clicked and the notification appears, i try to pull down the notifications bar and it lags. I don't know way but i think that it's because the notification check every second the battery level but i'm not sure.. I post the code:
#SuppressLint("NewApi")
private void checkPref(Intent intent){
this.registerReceiver(this.batteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
SharedPreferences myPref = PreferenceManager.getDefaultSharedPreferences(MainActivity.this);
boolean pref_opt1 = myPref.getBoolean("firstDependent", false);
int level= intent.getIntExtra(BatteryManager.EXTRA_LEVEL,-1);
if (pref_opt1){
NotificationManager notifi = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification.Builder(getApplicationContext())
.setContentTitle("Battery Informations")
.setContentText("Battery level"+" "+level+"%")
.setSmallIcon(R.drawable.icon_small_not)
//.setLargeIcon(aBitmap)
.setTicker(level+"%")
.build();
notification.flags = Notification.FLAG_ONGOING_EVENT;
Intent i = new Intent(MainActivity.this, MainActivity.class);
PendingIntent penInt = PendingIntent.getActivity(getApplicationContext(), 0 , i , 0);
notifi.notify(215,notification);
} else {
NotificationManager notifi = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
notifi.cancel(215);
}
}
Maybe the problem is this one this.registerReceiver(this.batteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));. But i know only this way to update the notification when the battery level changes.. Some helps please?
Check whether 'if-case' code to show notification is getting executed repeatedly. If so try limiting show notification to once via a flag value and reset the flag during notifi.cancel().
I've been fighting this for over a week now, so any help would be appreciated.
I have an Activity starting a Service for media playback. Once playback has begun, the Service starts an Ongoing, Non-Cancellable Notification as such:
realIntent = new Intent(this, EpisodeViewer.class);
realIntent.putExtra("show_name", showName);
realIntent.putExtra("episode_name", episodeName);
pendingIntent = PendingIntent.getActivity(this, 0, realIntent, 0);
note =
new Notification(
R.drawable.ic_notification_bcn,
episodeName,
System.currentTimeMillis());
note.flags =
note.flags |
Notification.FLAG_FOREGROUND_SERVICE |
Notification.FLAG_NO_CLEAR |
Notification.FLAG_ONGOING_EVENT;
note.setLatestEventInfo(this, "", episodeName, pendingIntent);
note.contentView =
new RemoteViews(
getApplicationContext().getPackageName(),
R.layout.episode_player_note);
note.contentView.setImageViewResource(
R.id.player_note_icon,
R.drawable.ic_notification_bcn);
note.contentView.setTextViewText(
R.id.player_note_text,
episodeName);
note.contentView.setProgressBar(
R.id.player_note_progress, 100, 0, false);
noteManager.notify(MEDIA_PLAYER_NOTIFY_ID, note);
And this works just fine. When the user switches to play something else (through the Activity's UI) the Service updates the Notification (using the same as above) to change the name and re-set the progress bar. And this works just fine. And as the media progresses, the progress bar in the Notification updates, and this works as well.
But when the media ends or the User wants to stop, the Service tries to cancel the Notification with
noteManager.cancel(MEDIA_PLAYER_NOTIFY_ID);
But this is ignored. There are no errors in the DDMS log, but from my trace I know for sure the cancel is being called. I've tried cancelling the PendingIntent before cancelling the Notification, but this makes no difference. I've also tried replacing the Notification with an 'Empty' one - clearing the progress and the name - and then cancelling. The new 'Cleared' Notification shows, but then still does not cancel.
So what am I missing here? Is there something else that needs to be done to cancel a FOREGROUND or NO_CLEAR or ONGOING Notification that I'm missing? I've tried this with the Emulator under 2.1 and 2.2, and on my hardware running 2.3, all of which exhibit the exact same behaviour.
I noticed the same problem.
If the notification flag has "Notification.FLAG_FOREGROUND_SERVICE" in it, the only way to get rid of it is to call "stopForeground()", but there is a catch. The "stopForeground()" won't remove the notification (with FLAG_FOREGROUND_SERVICE) if "startForeground()" has not been called!
In simple words, if you use FLAG_FOREGROUND_SERVICE, you have to call "startForeground()" and "stopForeground()"!
If "startForeground()" is used, I don't see a reason for putting FLAG_FOREGROUND_SERVICE in the other notifications. But if it is needed, here is a sample (used in public class CLASS extends Service) :
public int onStartCommand(Intent intent, int flags, int startId) {
PendingIntent notifIntent;
Intent notificationIntent = new Intent(); // fill up yourself
notifIntent = PendingIntent.getActivity(); // fill up yourself
Notification note = new Notification(); // fill up yourself
note.setLatestEventInfo(context, getString(R.string.app_name), Message, notifIntent);
startForeground(yourOwnNumber, note); // fill up yourself
displayYourNotification();
// Fill up the rest yourself.
}
public void onDestroy() {
stopForeground(); // fill up yourself
}
public void displayYourNotification() {
Intent notificationIntent = new Intent(); // fill up yourself
notifIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
Notification note = new Notification(); // fill up yourself
note.flags = Notification.FLAG_FOREGROUND_SERVICE;
note.setLatestEventInfo(context, TITLE, Message, notifIntent);
notifManager.notify(ID, note);
}
Can I create more than one notification in status bar from one program(Service) or I should create new Activity with a clickable list(for example LinearLayout) of objects?
You certainly can create more than one notification from a service or application, but you have to ask yourself is, as a user, you would want an application to spam notifications to you. I've been using one notification in my remote service and reusing the same notification by just updating its content. Here is an example:
public void onPlaybackStarted(int currentTrack, Show show) {
notificationManager.cancel(R.layout.notification_playing);
notification.tickerText = show.getTracks().get(currentTrack).getName();
if (notificationView == null) {
notificationView = new RemoteViews(getPackageName(), R.layout.notification_playing);
}
notificationView.setTextViewText(R.id.notification_playing_track, show.getTracks().get(currentTrack).getName());
notificationView.setTextViewText(R.id.notification_playing_band, show.getArtist());
notificationView.setTextViewText(R.id.notification_playing_date, show.getDate());
Intent intent = new Intent(TrackPlayerService.this, ListTracksActivity.class)
.putExtra("track", currentTrack)
.putExtra("artist", show.getArtist())
.putExtra("date", show.getDate())
.putExtra("location", show.getLocation())
.putExtra("venue", show.getVenue())
.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
notification.contentView = notificationView;
notification.contentIntent = PendingIntent.getActivity(TrackPlayerService.this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
notification.flags |= Notification.FLAG_ONGOING_EVENT;
notificationManager.notify(R.layout.notification_playing, notification);
}
If your notifications are not revolving, meaning you need to notify the user about 3 or 4 different things simultaneously, then having a notification that opens a ListActivity would be the best way to go.
I have a alarm manager which is calling an activity class named ScheduleAlert.
public class ScheduleAlert extends ActivityGroup {
private String notificationAlart, editEventid;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...........
..........
// ************* Notification ************//
NotificationManager mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
final Notification notifyDetails = new Notification(R.drawable.icon, "Myapp", nextAlarmTime);
Context context = getApplicationContext();
CharSequence contentTitle = "Myapp";
CharSequence contentText = notificationAlart;
Intent notifyIntent = new Intent(context, MyApp.class);
PendingIntent pendingIntent = PendingIntent.getActivity(ScheduleAlert.this, 0, notifyIntent,android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP);
notifyDetails.setLatestEventInfo(context, contentTitle, contentText,pendingIntent);
notifyDetails.flags = Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTO_CANCEL;
notifyDetails.defaults |= Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE;
mNotificationManager.notify((int) editEventid, notifyDetails);
// ************* Notification ************//
this.finish();
}
public void onDestroy(){
super.onDestroy();
}
}
I want that the indent of MyApp activity should fire when I tap on the notification massage. At the time of notification I want just sound and vibration. But now the I am getting the sound and vibration, and also the MyApp activity is fired, which I do not want actually. What is problem in my code?
There are lots and lots of strange things with this code:
I have no idea why you are extending ActivityGroup for this code
Do not use getApplicationContext() in most circumstances, such as this one
Since this is an ActivityGroup (for whatever reason) and not a Service, it is misleading to the OS and the user to have FLAG_FOREGROUND_SERVICE
FLAG_FOREGROUND_SERVICE and FLAG_AUTO_CANCEL make little sense in combination
However, I would not expect any of this to cause MyApp to automatically start. In fact, AFAIK, there is no circumstance in which a Notification will automatically invoke its PendingIntent without the user tapping on it. I suspect that your real problem lies elsewhere.
I have a service which creates a notification and then updates it with certain information periodically. After about 12 mins or so the phone crashes and reboots, I believe it is caused by a memory leak in the following code to do with how I am updating the notification, could someone please check/advise me if this is the case and what I am doing wrong.
onCreate:
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
createNotification:
private void createNotification() {
Intent contentIntent = new Intent(this,MainScreen.class);
contentIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent appIntent =PendingIntent.getActivity(this,0, contentIntent, 0);
contentView = new RemoteViews(getPackageName(), R.layout.notification);
contentView.setImageViewResource(R.id.image, R.drawable.icon);
contentView.setTextViewText(R.id.text, "");
notification = new Notification();
notification.when=System.currentTimeMillis();
notification.contentView = contentView;
notification.contentIntent = appIntent;
}
updateNotification:
private void updateNotification(String text){
contentView.setTextViewText(R.id.text, text);
mNotificationManager.notify(0, notification);
}
Thanks in advance.
I stumbled upon the same problem. Looks like that if you don't "cache" the RemoteView and Notification in the service, but re-create them from scratch in the "update" routine this problem disappears. Yes, I know it is not efficient, but at least the phone does not reboot from out of memory errors.
I had the very same problem. My solution is close to the one that #haimg said, but I do cache the notification (just the RemoteView is recreated). By doing so, the notification won't flash again if you are looking at it.
Example:
public void createNotification(Context context){
Notification.Builder builder = new Notification.Builder(context);
// Set notification stuff...
// Build the notification
notification = builder.build();
}
public void updateNotification(){
notification.bigContentView = getBigContentView();
notification.contentView = getCompactContentView();
mNM.notify(NOTIFICATION_ID, notification);
}
And in the methods getBigContentView and getCompactContentView I return a new RemoteViews with the updated layout.