Уведомление не отображается сразу даже при наличии уникального идентификатора
Я проверяю это много раз, используя журналы и предотвращаю notify()
метод менеджера вызывается несколько раз, если не требуется, чтобы избежать некоторых накладных расходов. Теперь у меня есть первое уведомление с прогрессом 0%, затем я снова создаю новое уведомление с прогрессом 0%, к сожалению, отображается только одно уведомление, даже если их идентификатор уникален, но позже, когда первый прогресс уведомления получает обновленный пример с 0% до 25%, тогда это единственный раз, когда он покажет желаемый результат, 2 уведомления с другим значением прогресса. Я использую только один Notification Manager, Notification Manager и в Notification Builder, поскольку не хочу создавать перекрывающуюся анимацию уведомления при его обновлении. Это ожидаемое поведение, когда на переднем плане?
public abstract class BaseTaskService extends Service {
private static final String TAG = "BaseTaskService";
private static final String CHANNEL_ID_DEFAULT = "Upload and Download";
private int queue = 0;
private FirebaseFirestore mDatabase;
private final List<Integer> listOfTaskID = new ArrayList<>();
private final SparseIntArray totalUnitList = new SparseIntArray();
private final SparseIntArray completedUnitList = new SparseIntArray();
private Notification notification;
private NotificationManager notificationManager;
private final NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, CHANNEL_ID_DEFAULT);
public void taskStarted(int id, boolean isUpload) {
//Increase the number of task
changeNumberOfTasks(1);
//Check if the task is new or not, if new then start a foreground service using id for it and add it to the list
if (!listOfTaskID.contains(id)){
listOfTaskID.add(id);
startForeground(id, notification);
Log.d(TAG, "Foreground Task Created : ID = " + id);
}
//If called by Upload Service, start the service once as a foreground per post
//If called by Download Service, start the service once as a foreground per file
if (isUpload){
//Set a total unit of files per post since one post could incorporate numerous images or files
totalUnitList.append(id, totalUnitList.get(id, 0) + 1);
Log.d(TAG, "Total Units For " + id + ": (" + totalUnitList.get(id) + ")");
}
}
public void taskCompleted() {
changeNumberOfTasks(-1);
}
private synchronized void changeNumberOfTasks(int delta) {
//Update the queue by adding delta value which could be 1 or -1
//Queue will display the overall upload or download of file from different tasks
queue += delta;
Log.d(TAG, "Overall Number of Remaining Task: " + queue);
//If there are no tasks left in queue, stop the service :)
if (queue <= 0) {
Log.d(TAG, "Stopping...");
//In Upload Service if there is no task in our queue it means that all request was finished
//so we need to reset the list of post's total task and completed task to zero
totalUnitList.clear();
completedUnitList.clear();
//Clear all of the id task
listOfTaskID.clear();
//Stop the foreground and remove all notification
stopForeground(true);
//Stop this service, calling this method will dismiss the very recent notification.
stopSelf();
}
}
@Override
public void onCreate() {
super.onCreate();
mDatabase = FirebaseFirestore.getInstance();
if (!isNotificationChannelEnabled(CHANNEL_ID_DEFAULT))
Toast.makeText(this, "Please turn on the notification in the app settings.", Toast.LENGTH_SHORT).show();
}
/*
We could use this line but unfortunately it will no longer work on Android O and above so we'll use the hashcode below.
This line is suppose to use for separating/detaching the Foreground notification from a Service
so that generating a separated unique id for PendingIntent and Finished notification is no longer needed.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
stopForeground(STOP_FOREGROUND_DETACH);
else
ServiceCompat.stopForeground(this, STOP_FOREGROUND_DETACH);
*/
//For Android O and above
private void createDefaultChannel() {
// Since Android Oreo notification channel is needed.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//If null then initialize the Notification Manager
if (notificationManager == null)
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel = new NotificationChannel(CHANNEL_ID_DEFAULT,
"Upload and Download",
NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
}
}
public boolean isNotificationChannelEnabled(String channelId){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if(channelId != null) {
NotificationManager manager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel = manager.getNotificationChannel(channelId);
return channel.getImportance() != NotificationManager.IMPORTANCE_NONE;
}
return false;
} else {
return NotificationManagerCompat.from(this).areNotificationsEnabled();
}
}
/**
* Show notification with a progress bar.
* Updating the progress happens here
* This is for DOWNLOAD SERVICE
*/
void showProgressNotification(String caption, long completedUnits, long totalUnits, int id) {
createDefaultChannel();
//If null then initialize the Notification Manager
if (notificationManager == null)
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
//Compute the progress
int percentComplete = 0;
if (totalUnits > 0) {
percentComplete = (int) (100 * completedUnits / totalUnits);
}
//To update and separate the notification progress according to its task
notification = notificationBuilder
.setProgress(100, percentComplete, false)
.setContentInfo(String.valueOf(percentComplete +"%"))
.setSmallIcon(R.drawable.ic_file_upload_white_24dp)
.setContentTitle(getString(R.string.app_name))
.setContentText(caption)
.setAutoCancel(false)
.setOngoing(true)
.build();
if (!listOfTaskID.contains(id))
Log.d(TAG, "Download Notification Created: ID = " + id);
else
Log.d(TAG, "Download Notification Updated: ID = " + id);
//Notify the manager that we have a new update with notification
notificationManager.notify(id, notification);
}
/**
* Show notification with a progress bar.
* Updating the progress happens here
* This is for UPLOAD SERVICE
*/
void showProgressNotification(String caption, final String path, final int id, boolean isComplete, String title, String desc) {
createDefaultChannel();
//If null then initialize the Notification Manager
if (notificationManager == null)
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
//Increment only if it is a successful task
if (isComplete)
completedUnitList.append(id, completedUnitList.get(id,0) + 1);
//Update and compute the progress
double percentComplete = 0;
if (totalUnitList.get(id, 0) > 0) {
//Perform this line if and only the total task is not equal to zero since dividing a number by zero is Error
percentComplete = (100 / totalUnitList.get(id)) * completedUnitList.get(id, 0);
}
notification = notificationBuilder
.setProgress(100, (int) percentComplete, false)
.setContentInfo(String.valueOf((int) percentComplete +"%"))
.setSmallIcon(R.drawable.ic_file_upload_white_24dp)
.setContentTitle(getString(R.string.app_name))
.setContentText(caption)
.setAutoCancel(false)
.setOngoing(true)
.build();
//This if condition is use to avoid repetitive call of notify() and will be triggered only if new task is created
if (!isComplete && !listOfTaskID.contains(id)){
Log.d(TAG, "Upload Notification Created: ID = " + id);
//Notify the manager that we have a new notification
notificationManager.notify(id, notification);
}
else if (isComplete){
Log.d(TAG, "Upload Notification Updated: ID = " + id);
//Notify the manager that we have a new update with notification
notificationManager.notify(id, notification);
//Check now if the number of completed task is equal to the number of total task if yes then show a finish notification
if (completedUnitList.get(id) == totalUnitList.get(id)){
Map<String, Object> details = new HashMap<>();
details.put(getResources().getString(R.string.Description), desc);
//We will use milliseconds to calculate how long is the post and for query
details.put(getResources().getString(R.string.Time_Posted), String.valueOf(new Date().getTime()));
details.put(getResources().getString(R.string.file), true);
if (title != null){
details.put(getResources().getString(R.string.Title),title);
details.put(getResources().getString(R.string.SU).toLowerCase(), Objects.requireNonNull(FirebaseAuth.getInstance().getCurrentUser()).getUid());
}
else
details.put(getResources().getString(R.string.uid), Objects.requireNonNull(FirebaseAuth.getInstance().getCurrentUser()).getUid());
//Make Intent to MainActivity
final Intent intent = new Intent(BaseTaskService.this, SUMain.class)
.putExtra(UploadService.DATA_COLLECTION, path)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
mDatabase.document(path).set(details).addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
showFinishedNotification(getString(R.string.upload_success), intent, true, id, true);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
showFinishedNotification(getString(R.string.upload_failure), intent, false, id, true);
}
});
}
}
}
/**
* Show notification that the activity finished.
*/
void showFinishedNotification(String caption, Intent intent, boolean isSuccess, int id, boolean isUpload) {
createDefaultChannel();
//Since calling a stopSelf() method will kill the service itself and dismissed the very recent Finished notification which is wrong in our case.
//Create a new id for Finished notification that is not bounded from the id of the progress notification, service, and foreground.
String uri = isUpload ? String.valueOf(intent.getParcelableExtra(UploadService.FILE_URI)) : String.valueOf(intent.getParcelableExtra(DownloadService.DOWNLOAD_URI));
//Use the hashcode of current timestamp mixed with some string to make it unique.
int newID = (uri + System.currentTimeMillis()).hashCode();
//Make PendingIntent for notification with the new generated unique id
PendingIntent pendingIntent = PendingIntent.getActivity(this, newID, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
int icon = isSuccess ? R.drawable.ic_done : R.drawable.ic_error_white_24dp;
notification = notificationBuilder
.setProgress(0, 0, false)
.setContentTitle(getString(R.string.app_name))
.setContentIntent(pendingIntent)
.setContentText(caption)
.setContentInfo(null)
.setAutoCancel(true)
.setSmallIcon(icon)
.setOngoing(false)
.build();
//Remove the first notification that has a incremental id which is the notification with progress
notificationManager.cancel(id);
//Show a new notification after removing the progress notification with the new generated unique id
notificationManager.notify(newID, notification);
Log.d(TAG, "Finished Notification: ID = " + newID);
}}