Skip to content

Commit

Permalink
更换 定时任务的实现
Browse files Browse the repository at this point in the history
  • Loading branch information
hyb1996 committed Dec 15, 2018
1 parent b79b25c commit 6f66956
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 86 deletions.
Binary file modified .idea/caches/build_file_checksums.ser
Binary file not shown.
2 changes: 2 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
7 changes: 0 additions & 7 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
3 changes: 2 additions & 1 deletion app/src/main/java/org/autojs/autojs/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -84,7 +85,7 @@ class App : MultiDexApplication() {
GlobalKeyObserver.init()
}
setupDrawableImageLoader()
TimedTaskScheduler.checkTasksRepeatedlyIfNeeded(this)
TimedTaskScheduler.init(this)
initDynamicBroadcastReceivers()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public TimedTaskDatabase(Context context) {
@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());
Expand All @@ -34,7 +35,7 @@ protected ContentValues asContentValues(TimedTask model) {
@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));
Expand Down
27 changes: 14 additions & 13 deletions app/src/main/java/org/autojs/autojs/timing/TimedTaskManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import io.reactivex.Flowable;
import io.reactivex.Observable;
import io.reactivex.functions.Consumer;

/**
* Created by Stardust on 2017/11/27.
Expand All @@ -41,14 +42,6 @@ public TimedTaskManager(Context context) {
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")
Expand Down Expand Up @@ -76,15 +69,17 @@ public void removeTask(TimedTask timedTask) {
@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);
}
Expand All @@ -95,7 +90,7 @@ public void addTask(IntentTask intentTask) {
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());
}
Expand Down Expand Up @@ -139,11 +134,17 @@ public void updateTask(TimedTask task) {
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);
}
Expand Down
147 changes: 86 additions & 61 deletions app/src/main/java/org/autojs/autojs/timing/TimedTaskScheduler.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,31 @@
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;
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;

Expand All @@ -20,24 +36,17 @@
* 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())
Expand All @@ -52,73 +61,89 @@ public static void scheduleTaskIfNeeded(Context context, TimedTask timedTask) {
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 cancel(Context context, TimedTask timedTask) {
Log.d(LOG_TAG, "cancel task: task = " + timedTask);
JobManager.instance().cancelAllForTag(String.valueOf(timedTask.getId()));
}

public static void checkTasksRepeatedlyIfNeeded(Context context) {
if (TimedTaskManager.getInstance().countTasks() > 0) {
setupNextRtcWakeup(context, System.currentTimeMillis() + 5000);
}
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 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);
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 class TimedTaskJob extends Job {

public static void cancel(Context context, TimedTask timedTask) {
AlarmManager alarmManager = getAlarmManager(context);
alarmManager.cancel(timedTask.createPendingIntent(context));
}
private final Context mContext;

public static void stopRtcRepeating(Context context) {
Log.v(LOG_TAG, "stopRtcRepeating");
AlarmManager alarmManager = getAlarmManager(context);
alarmManager.cancel(createTaskCheckPendingIntent(context));
}
TimedTaskJob(Context context) {
mContext = context;
}

private static AlarmManager getAlarmManager(Context context) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
assert alarmManager != null;
return alarmManager;
@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;
}
}

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 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;
}
return sCheckTasksPendingIntent;
}


}
2 changes: 1 addition & 1 deletion common/release/output.json
Original file line number Diff line number Diff line change
@@ -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":{}}]
4 changes: 2 additions & 2 deletions project-versions.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"appVersionCode": 453,
"appVersionName": "4.1.0 Alpha3",
"appVersionCode": 454,
"appVersionName": "4.1.0 Alpha4",
"target": 28,
"mini": 17,
"compile": 28,
Expand Down

0 comments on commit 6f66956

Please sign in to comment.