更换 定时任务的实现

This commit is contained in:
hyb1996
2018-12-15 16:45:01 +08:00
parent b79b25cfb3
commit 6f66956751
9 changed files with 112 additions and 89 deletions

View File

@@ -300,13 +300,6 @@
</intent-filter>
</receiver>
<receiver android:name=".timing.TimedTaskScheduler">
<intent-filter>
<action android:name="com.stardust.autojs.action.check_task"/>
<action android:name="com.android.deskclock.ALARM_ALERT"/>
</intent-filter>
</receiver>
</application>
</manifest>

View File

@@ -13,6 +13,7 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.SimpleTarget
import com.bumptech.glide.request.transition.Transition
import com.evernote.android.job.JobRequest
import com.flurry.android.FlurryAgent
import com.squareup.leakcanary.LeakCanary
import com.stardust.app.GlobalAppContext
@@ -84,7 +85,7 @@ class App : MultiDexApplication() {
GlobalKeyObserver.init()
}
setupDrawableImageLoader()
TimedTaskScheduler.checkTasksRepeatedlyIfNeeded(this)
TimedTaskScheduler.init(this)
initDynamicBroadcastReceivers()
}

View File

@@ -21,6 +21,7 @@ public class TimedTaskDatabase extends Database<TimedTask> {
@Override
protected ContentValues asContentValues(TimedTask model) {
ContentValues values = new ContentValues();
values.put("id", model.getId());
values.put("time", model.getTimeFlag());
values.put("scheduled", model.isScheduled());
values.put("delay", model.getDelay());
@@ -34,7 +35,7 @@ public class TimedTaskDatabase extends Database<TimedTask> {
@Override
protected TimedTask createModelFromCursor(Cursor cursor) {
TimedTask task = new TimedTask();
task.setId(cursor.getInt(0));
task.setId(cursor.getLong(0));
task.setTimeFlag(cursor.getLong(1));
task.setScheduled(cursor.getInt(2) != 0);
task.setDelay(cursor.getLong(3));

View File

@@ -17,6 +17,7 @@ import java.util.List;
import io.reactivex.Flowable;
import io.reactivex.Observable;
import io.reactivex.functions.Consumer;
/**
* Created by Stardust on 2017/11/27.
@@ -41,14 +42,6 @@ public class TimedTaskManager {
mContext = context;
mTimedTaskDatabase = new TimedTaskDatabase(context);
mIntentTaskDatabase = new IntentTaskDatabase(context);
mTimedTaskDatabase.getModelChange().subscribe(change -> {
int action = change.getAction();
if (action == ModelChange.DELETE && countTasks() == 0) {
TimedTaskScheduler.stopRtcRepeating(mContext);
} else if (action == ModelChange.INSERT) {
TimedTaskScheduler.checkTasksRepeatedlyIfNeeded(mContext);
}
});
}
@SuppressLint("CheckResult")
@@ -76,15 +69,17 @@ public class TimedTaskManager {
@SuppressLint("CheckResult")
public void addTask(TimedTask timedTask) {
mTimedTaskDatabase.insert(timedTask)
.subscribe(Observers.emptyConsumer(), Throwable::printStackTrace);;
TimedTaskScheduler.scheduleTaskIfNeeded(mContext, timedTask);
.subscribe(id -> {
timedTask.setId(id);
TimedTaskScheduler.scheduleTaskIfNeeded(mContext, timedTask);
}, Throwable::printStackTrace);
}
@SuppressLint("CheckResult")
public void addTask(IntentTask intentTask) {
mIntentTaskDatabase.insert(intentTask)
.subscribe(i -> {
if(!TextUtils.isEmpty(intentTask.getAction())){
if (!TextUtils.isEmpty(intentTask.getAction())) {
App.Companion.getApp().getDynamicBroadcastReceivers()
.register(intentTask);
}
@@ -95,7 +90,7 @@ public class TimedTaskManager {
public void removeTask(IntentTask intentTask) {
mIntentTaskDatabase.delete(intentTask)
.subscribe(i -> {
if(!TextUtils.isEmpty(intentTask.getAction())){
if (!TextUtils.isEmpty(intentTask.getAction())) {
App.Companion.getApp().getDynamicBroadcastReceivers()
.unregister(intentTask.getAction());
}
@@ -139,11 +134,17 @@ public class TimedTaskManager {
TimedTaskScheduler.scheduleTaskIfNeeded(mContext, task);
}
@SuppressLint("CheckResult")
public void updateTaskWithoutReScheduling(TimedTask task) {
mTimedTaskDatabase.update(task)
.subscribe(Observers.emptyConsumer(), Throwable::printStackTrace);
}
@SuppressLint("CheckResult")
public void updateTask(IntentTask task) {
mIntentTaskDatabase.update(task)
.subscribe(i -> {
if(i > 0 && !TextUtils.isEmpty(task.getAction())){
if (i > 0 && !TextUtils.isEmpty(task.getAction())) {
App.Companion.getApp().getDynamicBroadcastReceivers()
.register(task);
}

View File

@@ -3,6 +3,8 @@ package org.autojs.autojs.timing;
import android.annotation.SuppressLint;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -10,8 +12,22 @@ import android.os.Build;
import android.provider.AlarmClock;
import android.util.Log;
import com.evernote.android.job.Job;
import com.evernote.android.job.JobCreator;
import com.evernote.android.job.JobManager;
import com.evernote.android.job.JobRequest;
import com.evernote.android.job.util.support.PersistableBundleCompat;
import org.autojs.autojs.App;
import org.autojs.autojs.external.ScriptIntents;
import org.autojs.autojs.storage.database.TimedTaskDatabase;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.TimeUnit;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
@@ -20,24 +36,17 @@ import io.reactivex.schedulers.Schedulers;
* Created by Stardust on 2017/11/27.
*/
public class TimedTaskScheduler extends BroadcastReceiver {
public class TimedTaskScheduler {
public static final String ACTION_CHECK_TASK = "com.stardust.autojs.action.check_task";
private static final String LOG_TAG = "TimedTaskScheduler";
private static final int REQUEST_CODE_CHECK_TASK_REPEATEDLY = 4000;
private static final long INTERVAL = TimeUnit.MINUTES.toMillis(1);
private static final long ONE_HOUR = TimeUnit.HOURS.toMillis(1);
private static PendingIntent sCheckTasksPendingIntent;
@Override
public void onReceive(Context context, Intent intent) {
Log.d(LOG_TAG, "onReceiveRtcWakeup");
checkTasks(context);
setupNextRtcWakeup(context, System.currentTimeMillis() + INTERVAL);
}
private static final String JOB_TAG_CHECK_TASKS = "checkTasks";
@SuppressLint("CheckResult")
public static void checkTasks(Context context) {
Log.d(LOG_TAG, "check tasks");
TimedTaskManager.getInstance().getAllTasks()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
@@ -52,73 +61,89 @@ public class TimedTaskScheduler extends BroadcastReceiver {
scheduleTask(context, timedTask, millis);
TimedTaskManager.getInstance()
.notifyTaskScheduled(timedTask);
}
private static void scheduleTask(Context context, TimedTask timedTask, long millis) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
if (millis <= System.currentTimeMillis()) {
context.sendBroadcast(timedTask.createIntent());
private synchronized static void scheduleTask(Context context, TimedTask timedTask, long millis) {
if (timedTask.isScheduled()) {
return;
}
assert alarmManager != null;
// FIXME: 2017/11/28 requestCode may > 65535
PendingIntent op = timedTask.createPendingIntent(context);
setExactCompat(alarmManager, op, millis);
}
private static void setExactCompat(AlarmManager alarmManager, PendingIntent op, long millis) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, millis, op);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
alarmManager.setAlarmClock(new AlarmManager.AlarmClockInfo(millis, null), op);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, millis, op);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, millis, op);
long timeWindow = millis - System.currentTimeMillis();
Log.d(LOG_TAG, "schedule task: task = " + timedTask + ", millis = " + millis + ", timeWindow = " + timeWindow);
timedTask.setScheduled(true);
TimedTaskManager.getInstance().updateTaskWithoutReScheduling(timedTask);
if (timeWindow <= 0) {
runTask(context, timedTask);
return;
}
new JobRequest.Builder(String.valueOf(timedTask.getId()))
.setExact(timeWindow)
.build()
.schedule();
}
public static void checkTasksRepeatedlyIfNeeded(Context context) {
if (TimedTaskManager.getInstance().countTasks() > 0) {
setupNextRtcWakeup(context, System.currentTimeMillis() + 5000);
}
}
private static void setupNextRtcWakeup(Context context, long millis) {
Log.v(LOG_TAG, "setupNextRtcWakeup: at " + millis);
if (millis <= 0) {
throw new IllegalArgumentException("millis <= 0: " + millis);
}
AlarmManager alarmManager = getAlarmManager(context);
setExactCompat(alarmManager, createTaskCheckPendingIntent(context), millis);
}
public static void cancel(Context context, TimedTask timedTask) {
AlarmManager alarmManager = getAlarmManager(context);
alarmManager.cancel(timedTask.createPendingIntent(context));
Log.d(LOG_TAG, "cancel task: task = " + timedTask);
JobManager.instance().cancelAllForTag(String.valueOf(timedTask.getId()));
}
public static void stopRtcRepeating(Context context) {
Log.v(LOG_TAG, "stopRtcRepeating");
AlarmManager alarmManager = getAlarmManager(context);
alarmManager.cancel(createTaskCheckPendingIntent(context));
public static void init(@NotNull Context context) {
JobManager.create(context).addJobCreator(tag -> {
if (tag.equals(JOB_TAG_CHECK_TASKS)) {
return new CheckTasksJob(context);
} else {
return new TimedTaskJob(context);
}
});
new JobRequest.Builder(JOB_TAG_CHECK_TASKS)
.setPeriodic(TimeUnit.MINUTES.toMillis(20))
.build()
.scheduleAsync();
checkTasks(context);
}
private static AlarmManager getAlarmManager(Context context) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
assert alarmManager != null;
return alarmManager;
private static void runTask(Context context, TimedTask task) {
Log.d(LOG_TAG, "run task: task = " + task);
Intent intent = task.createIntent();
ScriptIntents.handleIntent(context, intent);
TimedTaskManager.getInstance().notifyTaskFinished(task.getId());
}
private static PendingIntent createTaskCheckPendingIntent(Context context) {
if (sCheckTasksPendingIntent == null) {
sCheckTasksPendingIntent = PendingIntent.getBroadcast(context, REQUEST_CODE_CHECK_TASK_REPEATEDLY,
new Intent(TimedTaskScheduler.ACTION_CHECK_TASK), PendingIntent.FLAG_UPDATE_CURRENT);
private static class TimedTaskJob extends Job {
private final Context mContext;
TimedTaskJob(Context context) {
mContext = context;
}
@NonNull
@Override
protected Result onRunJob(@NonNull Params params) {
long id = Long.parseLong(params.getTag());
TimedTask task = TimedTaskManager.getInstance().getTimedTask(id);
Log.d(LOG_TAG, "onRunJob: id = " + id + ", task = " + task);
if (task == null) {
return Result.FAILURE;
}
runTask(mContext, task);
return Result.SUCCESS;
}
return sCheckTasksPendingIntent;
}
private static class CheckTasksJob extends Job {
private final Context mContext;
CheckTasksJob(Context context) {
mContext = context;
}
@NonNull
@Override
protected Result onRunJob(@NonNull Params params) {
checkTasks(mContext);
return Result.SUCCESS;
}
}
}