更换 定时任务的实现
This commit is contained in:
BIN
.idea/caches/build_file_checksums.ser
generated
BIN
.idea/caches/build_file_checksums.ser
generated
Binary file not shown.
@@ -153,6 +153,8 @@ dependencies {
|
||||
implementation('com.afollestad.material-dialogs:commons:0.9.2.3', {
|
||||
exclude group: 'com.android.support'
|
||||
})
|
||||
// Android job
|
||||
implementation 'com.evernote:android-job:1.2.6'
|
||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.1'
|
||||
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.1'
|
||||
// Optional, if you use support library fragments:
|
||||
|
||||
@@ -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>
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":453,"versionName":"4.1.0 Alpha3","enabled":true,"outputFile":"commonRelease-4.1.0 Alpha3.apk","fullName":"commonRelease","baseName":"common-release"},"path":"commonRelease-4.1.0 Alpha3.apk","properties":{}}]
|
||||
[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":454,"versionName":"4.1.0 Alpha4","enabled":true,"outputFile":"commonRelease-4.1.0 Alpha4.apk","fullName":"commonRelease","baseName":"common-release"},"path":"commonRelease-4.1.0 Alpha4.apk","properties":{}}]
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"appVersionCode": 453,
|
||||
"appVersionName": "4.1.0 Alpha3",
|
||||
"appVersionCode": 454,
|
||||
"appVersionName": "4.1.0 Alpha4",
|
||||
"target": 28,
|
||||
"mini": 17,
|
||||
"compile": 28,
|
||||
|
||||
Reference in New Issue
Block a user