首页 > 解决方案 > 使用 WorkManager 触发推送通知有一些延迟

问题描述

我正在做一个示例项目来练习背景工作。首先,我使用了 FirebaseJobDispatcher,一切都很好。然后我知道了 WorkManager,它是目前进行后台工作的最佳方式。

我的应用程序的想法是用户输入他希望在之后触发通知的分钟数,使用 FirebaseJobDispatcher 时立即触发通知,但是当我切换到 WorkManager 时,通知延迟了近 20 秒 +用户已经进入的时间.. 换句话说,如果用户将触发器设置为 1 分钟然后关闭应用程序,则在 Activity 销毁后 20 秒重新开始倒计时.. 意味着将在 1 后触发通知: 20分钟。

这是 MainActivity 中的代码(使用 WorkManager):

            Data data = new Data.Builder()
                    .putInt("number", minutes*60)
                    .build();

            OneTimeWorkRequest oneTimeWorkRequest = new OneTimeWorkRequest.Builder(MyWorker.class)                     
                    .setInputData(data)                        
                    .addTag("timer")
                    .build();
            
            WorkManager.getInstance(MainActivity.this).enqueue(oneTimeWorkRequest);

MainActivity(使用 FirebaseJobDispatcher)

JobSchedulerUtils.scheduleNotification(MainActivity.this, minutes);

下面是扩展Worker的java类:

public class MyWorker extends Worker {
public MyWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
    super(context, workerParams);
}

@NonNull
@Override
/*
this is a simulation for background work, a countdown starts at a given number and this number decrements every second.
the process runs off of the main thread.
 */
public Result doWork() {
    // this is like an intent bundle, if you want to pass data from the activity to the Worker
    // in this app, the passed int is the number where we start countdown
    Data inputData = getInputData();
    int number = inputData.getInt("number", -1);

    for(int i = number; i >= 0; i--){
        Log.d("logmsg", i+"");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
            return Result.failure();
        }
    }

    TriggerTasks.executeTask(getApplicationContext(), TriggerTasks.TRIGGER_NOTIFICATION);
    return Result.success();
}

}

以下是使用 FirebaseJobDispatcher 时使用的类:

A- SchedulerFirebaseJobDispatcher.java

public class SchedulerFirebaseJobService extends JobService {

private AsyncTask mTask;
@Override
public boolean onStartJob(final JobParameters job) {

    mTask = new AsyncTask() {
        @Override
        protected Object doInBackground(Object[] objects) {
            // work to be done in background
            Context context = SchedulerFirebaseJobService.this;
            TriggerTasks.executeTask(context, TriggerTasks.TRIGGER_NOTIFICATION);
            return null;
        }

        @Override
        protected void onPostExecute(Object o) {
            super.onPostExecute(o);
            jobFinished(job, false);
        }
    };
    mTask.execute();
    return true;
}

@Override
public boolean onStopJob(JobParameters job) {
    if (mTask != null) mTask.cancel(true);
    return false;
}

}

B- JobSchedulerUtils.java

public class JobSchedulerUtils {
private static final String TRIGGER_NOTIFICATION_JOB_TAG = "trigger-notification";

synchronized public static void scheduleNotification(@NonNull final Context context, int time){

    Driver driver = new GooglePlayDriver(context);
    // TODO: use WorkManager instead of FirebaseJobDispatcher
    FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(driver);
    // job is triggered in the service so we set service to SchedulerFirebaseJobService, but here we define the parameters of this job
    // to be done in the background..
    // in other words, services's doInBackground is triggered using the following parameters and after the event in setTrigger occurs
    Job job = dispatcher.newJobBuilder().setService(SchedulerFirebaseJobService.class)
            .setTag(TRIGGER_NOTIFICATION_JOB_TAG)
            .setLifetime(Lifetime.FOREVER)
            .setRecurring(false)
            .setTrigger(Trigger.executionWindow(time*60, time*60))
            .setReplaceCurrent(true)
            .build();

    dispatcher.schedule(job);
}

}

以下是这两种情况下使用的其余类:

A- TriggerTasks.java

public class TriggerTasks {
public static final String DISMISS_NOTIFICATION = "dismiss-notification";
public static final String TRIGGER_NOTIFICATION = "trigger-notification";

public static void executeTask(Context context, String action){
    if(DISMISS_NOTIFICATION.equals(action)){
        NotificationUtils.clearAllNotifications(context);
    }
    if(TRIGGER_NOTIFICATION.equals(action)){
        NotificationUtils.createNotification(context);
    }
}

}

B- NotificationUtils.java

public class NotificationUtils {
private static final String NOTIFICATION_CHANNEL_ID = "notif-channel";
private static final String NOTIFICATION_CHANNEL_NAME = "Primary";
private static final int PENDING_INTENT_ID = 1991;
private static final int NOTIFICATION_ID = 500;
private static final int ACTION_IGNORE_PENDING_INTENT_ID = 24;

public static void clearAllNotifications(Context context){
    NotificationManager notificationManager = (NotificationManager)
            context.getSystemService(Context.NOTIFICATION_SERVICE);
    notificationManager.cancelAll();
}

public static void createNotification(Context context){
    NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
        NotificationChannel notificationChannel = new NotificationChannel(
                NOTIFICATION_CHANNEL_ID,
                NOTIFICATION_CHANNEL_NAME,
                NotificationManager.IMPORTANCE_HIGH
                );
        notificationManager.createNotificationChannel(notificationChannel);
    }


    NotificationCompat.Builder builder = new NotificationCompat.Builder(context,NOTIFICATION_CHANNEL_ID);
    builder.setAutoCancel(true)
            .setContentText(context.getString(R.string.notification_text))
            .setContentTitle(context.getString(R.string.notification_title))
            // this attribute controls what happens when a notification is clicked
            .setContentIntent(contentIntent(context))
            .setSmallIcon(R.drawable.ic_launcher_background)
            .addAction(dismissNotification(context));

    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
        builder.setPriority(NotificationCompat.PRIORITY_HIGH);
    }

    notificationManager.notify(NOTIFICATION_ID, builder.build());
}

/*
guarantees that a click on the notification will start MainActivity
 */
private static PendingIntent contentIntent(Context context){
    Intent toMainActivity = new Intent(context, MainActivity.class);
    return PendingIntent.getActivity(
            context,
            PENDING_INTENT_ID,
            toMainActivity,
            PendingIntent.FLAG_UPDATE_CURRENT);
}

private static NotificationCompat.Action dismissNotification (Context context){
    Intent intent = new Intent(context, TriggerIntentService.class);
    intent.setAction(TriggerTasks.DISMISS_NOTIFICATION);
    PendingIntent pendingIntent = PendingIntent.getService(
            context,
            ACTION_IGNORE_PENDING_INTENT_ID,
            intent,
            PendingIntent.FLAG_UPDATE_CURRENT);
    NotificationCompat.Action dismissNotificationAction = new NotificationCompat.Action(
            R.drawable.ic_launcher_foreground,
            context.getString(R.string.notification_action_dismiss),
            pendingIntent);
    return dismissNotificationAction;
}

}

C-TriggerIntentService.java

public class TriggerIntentService extends IntentService {

public TriggerIntentService() {
    super("TriggerIntentService");
}

@Override
protected void onHandleIntent(@Nullable Intent intent) {
    String action = intent.getAction();
    TriggerTasks.executeTask(this, action);
}

}

标签: javaandroidandroid-notificationsandroid-workmanagerbackground-task

解决方案


推荐阅读