更换 定时任务的实现
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', {
|
implementation('com.afollestad.material-dialogs:commons:0.9.2.3', {
|
||||||
exclude group: 'com.android.support'
|
exclude group: 'com.android.support'
|
||||||
})
|
})
|
||||||
|
// Android job
|
||||||
|
implementation 'com.evernote:android-job:1.2.6'
|
||||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.1'
|
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.1'
|
||||||
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.1'
|
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.1'
|
||||||
// Optional, if you use support library fragments:
|
// Optional, if you use support library fragments:
|
||||||
|
|||||||
@@ -300,13 +300,6 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</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>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -13,6 +13,7 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
|||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.bumptech.glide.request.target.SimpleTarget
|
import com.bumptech.glide.request.target.SimpleTarget
|
||||||
import com.bumptech.glide.request.transition.Transition
|
import com.bumptech.glide.request.transition.Transition
|
||||||
|
import com.evernote.android.job.JobRequest
|
||||||
import com.flurry.android.FlurryAgent
|
import com.flurry.android.FlurryAgent
|
||||||
import com.squareup.leakcanary.LeakCanary
|
import com.squareup.leakcanary.LeakCanary
|
||||||
import com.stardust.app.GlobalAppContext
|
import com.stardust.app.GlobalAppContext
|
||||||
@@ -84,7 +85,7 @@ class App : MultiDexApplication() {
|
|||||||
GlobalKeyObserver.init()
|
GlobalKeyObserver.init()
|
||||||
}
|
}
|
||||||
setupDrawableImageLoader()
|
setupDrawableImageLoader()
|
||||||
TimedTaskScheduler.checkTasksRepeatedlyIfNeeded(this)
|
TimedTaskScheduler.init(this)
|
||||||
initDynamicBroadcastReceivers()
|
initDynamicBroadcastReceivers()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ public class TimedTaskDatabase extends Database<TimedTask> {
|
|||||||
@Override
|
@Override
|
||||||
protected ContentValues asContentValues(TimedTask model) {
|
protected ContentValues asContentValues(TimedTask model) {
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
|
values.put("id", model.getId());
|
||||||
values.put("time", model.getTimeFlag());
|
values.put("time", model.getTimeFlag());
|
||||||
values.put("scheduled", model.isScheduled());
|
values.put("scheduled", model.isScheduled());
|
||||||
values.put("delay", model.getDelay());
|
values.put("delay", model.getDelay());
|
||||||
@@ -34,7 +35,7 @@ public class TimedTaskDatabase extends Database<TimedTask> {
|
|||||||
@Override
|
@Override
|
||||||
protected TimedTask createModelFromCursor(Cursor cursor) {
|
protected TimedTask createModelFromCursor(Cursor cursor) {
|
||||||
TimedTask task = new TimedTask();
|
TimedTask task = new TimedTask();
|
||||||
task.setId(cursor.getInt(0));
|
task.setId(cursor.getLong(0));
|
||||||
task.setTimeFlag(cursor.getLong(1));
|
task.setTimeFlag(cursor.getLong(1));
|
||||||
task.setScheduled(cursor.getInt(2) != 0);
|
task.setScheduled(cursor.getInt(2) != 0);
|
||||||
task.setDelay(cursor.getLong(3));
|
task.setDelay(cursor.getLong(3));
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import io.reactivex.Flowable;
|
import io.reactivex.Flowable;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
|
import io.reactivex.functions.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Stardust on 2017/11/27.
|
* Created by Stardust on 2017/11/27.
|
||||||
@@ -41,14 +42,6 @@ public class TimedTaskManager {
|
|||||||
mContext = context;
|
mContext = context;
|
||||||
mTimedTaskDatabase = new TimedTaskDatabase(context);
|
mTimedTaskDatabase = new TimedTaskDatabase(context);
|
||||||
mIntentTaskDatabase = new IntentTaskDatabase(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")
|
@SuppressLint("CheckResult")
|
||||||
@@ -76,15 +69,17 @@ public class TimedTaskManager {
|
|||||||
@SuppressLint("CheckResult")
|
@SuppressLint("CheckResult")
|
||||||
public void addTask(TimedTask timedTask) {
|
public void addTask(TimedTask timedTask) {
|
||||||
mTimedTaskDatabase.insert(timedTask)
|
mTimedTaskDatabase.insert(timedTask)
|
||||||
.subscribe(Observers.emptyConsumer(), Throwable::printStackTrace);;
|
.subscribe(id -> {
|
||||||
TimedTaskScheduler.scheduleTaskIfNeeded(mContext, timedTask);
|
timedTask.setId(id);
|
||||||
|
TimedTaskScheduler.scheduleTaskIfNeeded(mContext, timedTask);
|
||||||
|
}, Throwable::printStackTrace);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("CheckResult")
|
@SuppressLint("CheckResult")
|
||||||
public void addTask(IntentTask intentTask) {
|
public void addTask(IntentTask intentTask) {
|
||||||
mIntentTaskDatabase.insert(intentTask)
|
mIntentTaskDatabase.insert(intentTask)
|
||||||
.subscribe(i -> {
|
.subscribe(i -> {
|
||||||
if(!TextUtils.isEmpty(intentTask.getAction())){
|
if (!TextUtils.isEmpty(intentTask.getAction())) {
|
||||||
App.Companion.getApp().getDynamicBroadcastReceivers()
|
App.Companion.getApp().getDynamicBroadcastReceivers()
|
||||||
.register(intentTask);
|
.register(intentTask);
|
||||||
}
|
}
|
||||||
@@ -95,7 +90,7 @@ public class TimedTaskManager {
|
|||||||
public void removeTask(IntentTask intentTask) {
|
public void removeTask(IntentTask intentTask) {
|
||||||
mIntentTaskDatabase.delete(intentTask)
|
mIntentTaskDatabase.delete(intentTask)
|
||||||
.subscribe(i -> {
|
.subscribe(i -> {
|
||||||
if(!TextUtils.isEmpty(intentTask.getAction())){
|
if (!TextUtils.isEmpty(intentTask.getAction())) {
|
||||||
App.Companion.getApp().getDynamicBroadcastReceivers()
|
App.Companion.getApp().getDynamicBroadcastReceivers()
|
||||||
.unregister(intentTask.getAction());
|
.unregister(intentTask.getAction());
|
||||||
}
|
}
|
||||||
@@ -139,11 +134,17 @@ public class TimedTaskManager {
|
|||||||
TimedTaskScheduler.scheduleTaskIfNeeded(mContext, task);
|
TimedTaskScheduler.scheduleTaskIfNeeded(mContext, task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("CheckResult")
|
||||||
|
public void updateTaskWithoutReScheduling(TimedTask task) {
|
||||||
|
mTimedTaskDatabase.update(task)
|
||||||
|
.subscribe(Observers.emptyConsumer(), Throwable::printStackTrace);
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressLint("CheckResult")
|
@SuppressLint("CheckResult")
|
||||||
public void updateTask(IntentTask task) {
|
public void updateTask(IntentTask task) {
|
||||||
mIntentTaskDatabase.update(task)
|
mIntentTaskDatabase.update(task)
|
||||||
.subscribe(i -> {
|
.subscribe(i -> {
|
||||||
if(i > 0 && !TextUtils.isEmpty(task.getAction())){
|
if (i > 0 && !TextUtils.isEmpty(task.getAction())) {
|
||||||
App.Companion.getApp().getDynamicBroadcastReceivers()
|
App.Companion.getApp().getDynamicBroadcastReceivers()
|
||||||
.register(task);
|
.register(task);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package org.autojs.autojs.timing;
|
|||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.AlarmManager;
|
import android.app.AlarmManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
|
import android.app.job.JobInfo;
|
||||||
|
import android.app.job.JobScheduler;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -10,8 +12,22 @@ import android.os.Build;
|
|||||||
import android.provider.AlarmClock;
|
import android.provider.AlarmClock;
|
||||||
import android.util.Log;
|
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 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.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
|
||||||
@@ -20,24 +36,17 @@ import io.reactivex.schedulers.Schedulers;
|
|||||||
* Created by Stardust on 2017/11/27.
|
* 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 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 final long ONE_HOUR = TimeUnit.HOURS.toMillis(1);
|
||||||
private static PendingIntent sCheckTasksPendingIntent;
|
|
||||||
|
|
||||||
@Override
|
private static final String JOB_TAG_CHECK_TASKS = "checkTasks";
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
Log.d(LOG_TAG, "onReceiveRtcWakeup");
|
|
||||||
checkTasks(context);
|
|
||||||
setupNextRtcWakeup(context, System.currentTimeMillis() + INTERVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("CheckResult")
|
@SuppressLint("CheckResult")
|
||||||
public static void checkTasks(Context context) {
|
public static void checkTasks(Context context) {
|
||||||
|
Log.d(LOG_TAG, "check tasks");
|
||||||
TimedTaskManager.getInstance().getAllTasks()
|
TimedTaskManager.getInstance().getAllTasks()
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
@@ -52,73 +61,89 @@ public class TimedTaskScheduler extends BroadcastReceiver {
|
|||||||
scheduleTask(context, timedTask, millis);
|
scheduleTask(context, timedTask, millis);
|
||||||
TimedTaskManager.getInstance()
|
TimedTaskManager.getInstance()
|
||||||
.notifyTaskScheduled(timedTask);
|
.notifyTaskScheduled(timedTask);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private synchronized static void scheduleTask(Context context, TimedTask timedTask, long millis) {
|
||||||
private static void scheduleTask(Context context, TimedTask timedTask, long millis) {
|
if (timedTask.isScheduled()) {
|
||||||
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
|
||||||
if (millis <= System.currentTimeMillis()) {
|
|
||||||
context.sendBroadcast(timedTask.createIntent());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
assert alarmManager != null;
|
long timeWindow = millis - System.currentTimeMillis();
|
||||||
// FIXME: 2017/11/28 requestCode may > 65535
|
Log.d(LOG_TAG, "schedule task: task = " + timedTask + ", millis = " + millis + ", timeWindow = " + timeWindow);
|
||||||
PendingIntent op = timedTask.createPendingIntent(context);
|
timedTask.setScheduled(true);
|
||||||
setExactCompat(alarmManager, op, millis);
|
TimedTaskManager.getInstance().updateTaskWithoutReScheduling(timedTask);
|
||||||
}
|
if (timeWindow <= 0) {
|
||||||
|
runTask(context, timedTask);
|
||||||
private static void setExactCompat(AlarmManager alarmManager, PendingIntent op, long millis) {
|
return;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
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) {
|
public static void cancel(Context context, TimedTask timedTask) {
|
||||||
AlarmManager alarmManager = getAlarmManager(context);
|
Log.d(LOG_TAG, "cancel task: task = " + timedTask);
|
||||||
alarmManager.cancel(timedTask.createPendingIntent(context));
|
JobManager.instance().cancelAllForTag(String.valueOf(timedTask.getId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void stopRtcRepeating(Context context) {
|
public static void init(@NotNull Context context) {
|
||||||
Log.v(LOG_TAG, "stopRtcRepeating");
|
JobManager.create(context).addJobCreator(tag -> {
|
||||||
AlarmManager alarmManager = getAlarmManager(context);
|
if (tag.equals(JOB_TAG_CHECK_TASKS)) {
|
||||||
alarmManager.cancel(createTaskCheckPendingIntent(context));
|
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) {
|
private static void runTask(Context context, TimedTask task) {
|
||||||
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
Log.d(LOG_TAG, "run task: task = " + task);
|
||||||
assert alarmManager != null;
|
Intent intent = task.createIntent();
|
||||||
return alarmManager;
|
ScriptIntents.handleIntent(context, intent);
|
||||||
|
TimedTaskManager.getInstance().notifyTaskFinished(task.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PendingIntent createTaskCheckPendingIntent(Context context) {
|
private static class TimedTaskJob extends Job {
|
||||||
if (sCheckTasksPendingIntent == null) {
|
|
||||||
sCheckTasksPendingIntent = PendingIntent.getBroadcast(context, REQUEST_CODE_CHECK_TASK_REPEATEDLY,
|
private final Context mContext;
|
||||||
new Intent(TimedTaskScheduler.ACTION_CHECK_TASK), PendingIntent.FLAG_UPDATE_CURRENT);
|
|
||||||
|
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,
|
"appVersionCode": 454,
|
||||||
"appVersionName": "4.1.0 Alpha3",
|
"appVersionName": "4.1.0 Alpha4",
|
||||||
"target": 28,
|
"target": 28,
|
||||||
"mini": 17,
|
"mini": 17,
|
||||||
"compile": 28,
|
"compile": 28,
|
||||||
|
|||||||
Reference in New Issue
Block a user