0

我使用 Logs 多次检查它,并防止在notify()不需要时多次调用 manager 的方法以避免一些开销。现在我有第一个进度为 0% 的通知,然后我再次创建一个进度为 0% 的新通知,不幸的是,即使它们的 id 是唯一的,也只显示一个通知,但稍后当第一个通知进度更新示例从 0% 到25% 那么这是它唯一一次显示所需的输出,即具有不同进度值的 2 个通知。我只使用一个通知、通知管理器和通知生成器,因为我不想在通知更新时创建通知的重叠动画。这是在前台时的预期行为吗?

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);

}}
4

0 回答 0