定期工作管理器在未充电或屏幕关闭时未在Android Pie上显示通知

时间:2019-01-03 15:53:07

标签: android android-workmanager xiaomi

我有一个应用程序,该应用程序每2小时显示一次通知,如果用户已经对通知进行了操作,则应停止运行。由于后台服务已成为历史,因此我想到了同时使用WorkManager("android.arch.work:work-runtime:1.0.0-beta01")。

我的问题是,尽管工作经理在应用程序运行时成功显示了通知,但在以下情况下却无法始终显示通知(我将检查时间从2小时缩短为2分钟,以确保一致性) :

  • 当应用被后台杀死时。
  • 设备处于屏幕关闭状态。
  • 状态设备处于拔出状态(即不充电)。

通过一致性,我的意思是通知在给定的时间范围内至少显示一次。在2分钟的时间范围内,通知频率从每4分钟一次变为完全不显示任何通知。 2个小时的时间跨度(我实际想要的时间跨度),已经4个小时了,我还没有收到任何通知。这是我用来调用WorkManger的代码:

    public class CurrentStreakActivity extends AppCompatActivity {
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...

        setDailyNotifier();
        ...
    }

    private void setDailyNotifier() {
        Constraints.Builder constraintsBuilder = new Constraints.Builder();
        constraintsBuilder.setRequiresBatteryNotLow(false);
        constraintsBuilder.setRequiredNetworkType(NetworkType.NOT_REQUIRED);
        constraintsBuilder.setRequiresCharging(false);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            constraintsBuilder.setRequiresDeviceIdle(false);
        }

        Constraints constraints =constraintsBuilder.build();


        PeriodicWorkRequest.Builder builder = new PeriodicWorkRequest
                .Builder(PeriodicNotifyWorker.class, 2, TimeUnit.HOURS);

        builder.setConstraints(constraints);
        WorkRequest request = builder.build();
        WorkManager.getInstance().enqueue(request);

    }
    ....
}

这是工作者类(如果它们可能有错误,我也可以发布showNotif(..)setNotificationChannel(...)):

public class CurrentStreakActivity extends AppCompatActivity {
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...

        setDailyNotifier();
        ...
    }

    private void setDailyNotifier() {
        Constraints.Builder constraintsBuilder = new Constraints.Builder();
        constraintsBuilder.setRequiresBatteryNotLow(false);
        constraintsBuilder.setRequiredNetworkType(NetworkType.NOT_REQUIRED);
        constraintsBuilder.setRequiresCharging(false);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            constraintsBuilder.setRequiresDeviceIdle(false);
        }

        Constraints constraints =constraintsBuilder.build();


        PeriodicWorkRequest.Builder builder = new PeriodicWorkRequest
                .Builder(PeriodicNotifyWorker.class, 2, TimeUnit.HOURS);

        builder.setConstraints(constraints);
        WorkRequest request = builder.build();
        WorkManager.getInstance().enqueue(request);

    }
    ....
}

public class PeriodicNotifyWorker extends Worker {
    private static final String TAG = "PeriodicNotifyWorker";

    public PeriodicNotifyWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
        Log.e(TAG, "PeriodicNotifyWorker: constructor called" );
    }

    @NonNull
    @Override
    public Result doWork() {
//        Log.e(TAG, "doWork: called" );

        SharedPreferences sp =
                getApplicationContext().getSharedPreferences(Statics.SP_FILENAME, Context.MODE_PRIVATE);
        String lastcheckin = sp.getString(Statics.LAST_CHECKIN_DATE_str, Statics.getToday());
//        Log.e(TAG, "doWork: checking shared preferences for last checkin:"+lastcheckin );

        if (Statics.compareDateStrings(lastcheckin, Statics.getToday()) == -1) {
            Log.e(TAG, "doWork: last checkin is smaller than today's date, so calling creating notification" );
            return createNotificationWithButtons(sp);
        }
        else {
            Log.e(TAG, "doWork: last checkin is bigger than today's date, so no need for notif" );
            return Result.success();
        }
    }


    private Result createNotificationWithButtons(SharedPreferences sp) {
        NotificationManager manager =
                (NotificationManager) getApplicationContext().getSystemService((NOTIFICATION_SERVICE));
        String channel_ID = "100DaysOfCode_ID";
        if (manager != null) {
            setNotificationChannel(manager,channel_ID);
            showNotif(manager, channel_ID, sp);
            return Result.success();
        }
        else {
            return Result.failure();
        }

我正在将小米miA2 androidOne设备与Android Pie(SDK 28)配合使用。还有其他一些令我困扰的事情:

  • 我应该怎么做才能知道我的WorkManager是否正在运行?其他的只是等待2个小时,希望收到通知。实际上,我尝试过类似的操作,将手机保持与PC的连接,并不时检查android studio的logcat。确实在调用工人时会运行所有日志,但是我认为这不是测试它的正确方法,还是吗?
  • 在上述代码中,每次打开应用程序时,都会从setDailyNotifier()中调用onCreate()。是不是不对?是否应该为每个WorkRequest都没有一个唯一的ID以及像WorkManger.isRequestRunning(request.getID)这样的检查函数,它可以让我们检查工人是否已经在给定的任务上?如果这是{{1 }},那么男孩,我们将一团糟。

我还检查了@commonsware的答案here(如果您正在阅读此书,请注意@psons的忠实粉丝,先生,如果您正在阅读),但是我记得工作经理确实在其中使用了警报管理器。内部(如果有)。那我在这里想念什么?

2 个答案:

答案 0 :(得分:1)

少量评论:
WorkManager的最小定期间隔为15分钟,并且不能保证在准确的时间执行您的任务。您可以在this blog上了解有关此内容的更多信息。

使用WorkManager安排任务时,在较新的Android版本上具有的所有通常的背景限制仍然有用。 WorkManager保证即使应用程序被杀死或设备已恢复也可以执行任务,但是它不能保证确切的执行。

关于您的应用程序被终止时要重新安排任务的注意事项之一。一些OEM对OS和Launcher应用程序进行了修改,以防止WorkManager能够完成这些功能。

Here's the issuetracker discussion

  

是的,即使电话是中文电话也是如此。
  我们遇到的唯一问题是一些中国OEM将轻击从“最近”中解雇为强制停止的情况。发生这种情况时,WorkManager将在下次启动应用程序时重新计划所有待处理的作业。鉴于这是CDD的违规行为,因此只要有一个客户端库,WorkManager便无能为力。

     

此外,如果设备制造商决定修改库存的Android以强制停止应用程序,WorkManager将停止工作(JobScheduler,警报,广播接收器等也将停止工作)。没有办法解决此问题。不幸的是,某些设备制造商会这样做,因此在这种情况下,WorkManager将停止工作,直到下次启动该应用程序为止。

答案 1 :(得分:0)

截至目前,我已经在过去8天内安装了此应用,可以确认该代码正确并且该应用运行正常。如pfmaggi所述,工作经理安排工作的最短时间间隔为15分钟,因此WorkManager在我的测试条件下(如2分钟)按预期工作的可能性较小)。这是我的其他一些观察结果:

  • 就像我在问题中说的那样,即使我已将重复间隔设为2小时,但我仍无法在4个小时内收到通知。这是因为Flex Time。我输入了15分钟的弹性时间,现在它显示了正确时间间隔之间的通知。所以我将pfmaggi的答案标记为正确。
  • 可以通过将WorkManager.getInstance().enqueue(request)替换为WorkManager.getInstance().enqueueUniqueWork(request,..)

  • 来解决重复工作的问题。
  • 我仍然找不到以我所描述的方式测试工作经理的方法。