【问题标题】:Background service not running may be because of doze mode后台服务未运行可能是因为打盹模式
【发布时间】:2020-03-13 04:59:01
【问题描述】:

我想在晚上 11:59 准确地在服务器上上传一些数据。在这个时候我想收集数据,只要互联网可用,它就应该上传数据。首选是使用WorkManager 但是,我无法将其设置为准确的时间。对于确切的时间,我们必须使用AlarmManager,并且我们必须为互联网实现我们自己的逻辑或广播接收器。

所以,我正在使用 AlarmManager 设置 OneTimeWorkRequest。但问题是它不能在后台工作,而当应用程序在前台时工作正常。

清单

<service android:name=".Home.services.WorkerService"
        android:enabled="true"
        android:exported="true"/>

从片段开始服务

 private void setUpService(){
    Calendar calendar = Calendar.getInstance();
    calendar.set(Calendar.HOUR_OF_DAY,23);
    calendar.set(Calendar.MINUTE,59);
    Intent intent = new Intent(getActivity(), WorkerService.class);
    PendingIntent pendingIntent;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) pendingIntent = PendingIntent.getForegroundService(getActivity(),0,intent,0);
    else pendingIntent = PendingIntent.getService(getActivity(),0,intent,0);
    AlarmManager alarmManager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
    assert alarmManager != null;
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(),AlarmManager.INTERVAL_DAY,pendingIntent);
}

工作服务

public class WorkerService extends Service {

AppDatabase database;

@Override
public void onCreate() {
    super.onCreate();

    database = AppDatabase.getInstance(this);

    readSteps();

    Constraints constraints = new Constraints.Builder()
            .setRequiredNetworkType(NetworkType.CONNECTED)
            .build();

    int user_id = database.getUserDao().getSuperUser().id;
    Date date = new Date();
    String formattedDate = String.valueOf(DateFormat.format("yyyy-MM-dd",date));

    float steps = database.getFitnessDao().getDateData(date,user_id).getSteps();
    Data data = new Data.Builder()
            .putInt("user_id",user_id)
            .putString("date",formattedDate)
            .putFloat("steps",steps)
            .build();

    OneTimeWorkRequest oneTimeWorkRequest = new OneTimeWorkRequest.Builder(StepWorker.class)
            .setConstraints(constraints)
            .setInputData(data)
            .build();

    WorkManager.getInstance(this).enqueue(oneTimeWorkRequest);
}

private void readSteps(){
    Fitness.getHistoryClient(this, GoogleSignIn.getLastSignedInAccount(this))
            .readDailyTotal(DataType.TYPE_STEP_COUNT_DELTA)
            .addOnSuccessListener(dataSet -> {
                int super_user = database.getUserDao().getSuperUser().id;
                float total = dataSet.isEmpty() ? 0 : dataSet.getDataPoints().get(0).getValue(Field.FIELD_STEPS).asInt();
                database.getFitnessDao().updateSteps(super_user,total,new Date());
            })
            .addOnFailureListener(e -> {
            });
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}
}

【问题讨论】:

    标签: android service android-service android-workmanager


    【解决方案1】:

    您需要修改您的服务类WorkerService 以在后台连续运行我已经编辑了您的服务类,使用它

        public class WorkerService extends Service {
    
        AppDatabase database;
    
        @Override
            public int onStartCommand(Intent intent, int flags, int startId) {
    
    
            database = AppDatabase.getInstance(this);
    
            readSteps();
        Handler handler = new Handler();
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
    // check here the device current time is equal to 11:59 Pm or not 
    // run your code if current current time is equal to 11:59
                handler.postDelayed(this, 30000);
    
        }
    }, 30000); // every 30 seconds
    
           return START_STICKY;
        }
    
    
        private void readSteps(){
            Fitness.getHistoryClient(this, GoogleSignIn.getLastSignedInAccount(this))
                    .readDailyTotal(DataType.TYPE_STEP_COUNT_DELTA)
                    .addOnSuccessListener(dataSet -> {
                        int super_user = database.getUserDao().getSuperUser().id;
                        float total = dataSet.isEmpty() ? 0 : dataSet.getDataPoints().get(0).getValue(Field.FIELD_STEPS).asInt();
                        database.getFitnessDao().updateSteps(super_user,total,new Date());
                    })
                    .addOnFailureListener(e -> {
                    });
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
            @Override
            public void onCreate() {
                super.onCreate();
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    startMyOwnForeground();
                } else {
                    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, "1");
                    Notification notification = notificationBuilder.setOngoing(true)
                            .setSmallIcon(R.mipmap.ic_launcher)
                            .setPriority(NotificationManager.IMPORTANCE_MIN)
                            .setCategory(Notification.CATEGORY_SERVICE)
                            .build();
                    startForeground(1, notification);
                }
            }
          @RequiresApi(api = Build.VERSION_CODES.O)
            private void startMyOwnForeground() {
                String channelName = "BackgroundService";
                NotificationChannel chan = new NotificationChannel("2", channelName, NotificationManager.IMPORTANCE_NONE);
                chan.setLightColor(Color.BLUE);
                chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
                NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
                assert manager != null;
                manager.createNotificationChannel(chan);
    
                NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, "2");
                Notification notification = notificationBuilder.setOngoing(true)
                        .setSmallIcon(R.mipmap.ic_launcher)
                        .setPriority(NotificationManager.IMPORTANCE_MIN)
                        .setCategory(Notification.CATEGORY_SERVICE)
                        .build();
                startForeground(2, notification);
            }
          @Override
            public void onTaskRemoved(Intent rootIntent) {
                Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
                restartServiceIntent.setPackage(getPackageName());        
                PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
                AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
                alarmService.set(
                        AlarmManager.ELAPSED_REALTIME,
                        SystemClock.elapsedRealtime() + 1000,
                        restartServicePendingIntent);
    
                super.onTaskRemoved(rootIntent);
            }
        }
    

    现在像这样在片段中启动服务

    startService(new Intent(context, WorkerService.class));
    

    【讨论】:

    • 如果我每 30 秒检查一次,它不会消耗太多电池吗?我不可能使用 AlarmManager 在准确的时间触发前台服务?
    • 是的,它会耗尽电池电量,但什么是设备已经处于打盹模式?在这种情况下,警报管理器可能不起作用,因此需要后台服务来处理打盹模式
    【解决方案2】:

    没有什么可以让您选择确切的时间,除非您被 Doze 列入白名单。这必须由用户完成,而不是应用程序。 Alarms 和 WorkManager 都受其影响。如果在应该完成闹钟或工作时手机处于关机状态,如果应用未列入白名单,它将等待下一个打盹窗口。

    【讨论】:

    • 那么运行此服务的最佳解决方案应该是什么?我不确定它没有运行,只是因为打盹模式。
    • 你应该使用前台服务,因为android对bg服务应用了限制,如果你想安排一个任务或者想要执行一些操作,其他的事情就是和工作经理一起去。系统将寻找合适的时间,包括所有的约束打瞌睡模式等。这将保证执行,但时间不准确。
    • 最好的替代方法是运行后台并在时间等于所需时间时每 30 秒检查一次当前时间,如果打瞌睡模式给您带来问题,请执行您的工作
    猜你喜欢
    • 2019-11-13
    • 2016-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-06
    • 2019-05-16
    • 2019-04-25
    • 1970-01-01
    相关资源
    最近更新 更多