I have an app that downloads data from an online database. It uses PeriodicWorkRequest and it doesn't work as expected. I use WorkManager 2.3.0.
There is my WorkManager settings
public class ReminderUtil {
public static final String ARTICLE_WORK_TAG = "article_work";
public static void scheduleReminder(Context context) {
PeriodicWorkRequest request = new PeriodicWorkRequest
.Builder(ArticleWorker.class, 120, MINUTES, 10, MINUTES)
.setInitialDelay(1, MINUTES)
.build();
WorkManager.getInstance(context).enqueueUniquePeriodicWork(ARTICLE_WORK_TAG,
ExistingPeriodicWorkPolicy.KEEP, request);
}
Worker class
public class ArticleWorker extends Worker {
private Context mContext;
public ArticleWorker(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
mContext = context;
}
#NonNull
#Override
public Result doWork() {
//downloading new article date list
List<ArticleLight> recentArticleLightList = QueryUtils.getArticlesLight(ArticleUtils.articleUrl);
//sorting by Date
Collections.sort(recentArticleLightList, (o1, o2) -> o2.getDate().compareTo(o1.getDate()));
Date newestDate = recentArticleLightList.get(0).getDate();
String articleText = recentArticleLightList.get(0).getTitle();
//compare newestDate with last saved sate
SharedPreferences prefs = mContext.getSharedPreferences("MyPref", Context.MODE_PRIVATE);
long savedDateLong = prefs.getLong("date", 0);
savedDateLong = savedDateLong - 604800000;//todo this is a notification test
Date savedDate = new Date(savedDateLong);
Log.i("myTAG", "WORKER");
if (newestDate.compareTo(savedDate) > 0) {
//we have new article!
NotificationUtil.createNotification(mContext, articleText);
Log.i("myTAG", "NOTIFICATION");
}
return Result.success();
}
}
And there is my log
2020-02-02 15:34:39.506 29571-7035/com.g84.spacenewstheguardian I/myTAG: WORKER
2020-02-02 15:34:39.521 29571-7035/com.g84.spacenewstheguardian I/myTAG: NOTIFICATION
2020-02-02 15:50:00.983 29571-31372/com.g84.spacenewstheguardian I/myTAG: WORKER
2020-02-02 15:50:00.998 29571-31372/com.g84.spacenewstheguardian I/myTAG: NOTIFICATION
2020-02-02 16:05:01.981 29571-337/com.g84.spacenewstheguardian I/myTAG: WORKER
2020-02-02 16:05:01.995 29571-337/com.g84.spacenewstheguardian I/myTAG: NOTIFICATION
2020-02-02 16:20:32.641 29571-3899/com.g84.spacenewstheguardian I/myTAG: WORKER
2020-02-02 16:20:32.710 29571-3899/com.g84.spacenewstheguardian I/myTAG: NOTIFICATION
As you can see the worker should run every 120 minutes with 10 minutes flexi time but it runs approximately every 16 minutes.
EDIT:
My goal is create a daily request at a specific time. So I tried to change the PeriodicWorkRequest to OneTimeWorkRequest.
When app is installed, it triggers the OneTimeWorkRequest with calculated initialDelay to a required hour. When the Worker is triggered, it sets new OneTimeWorkRequest (again with calculated initialDelay).
So far it works as I require, but still testing.
public class ReminderUtil {
public static final String ARTICLE_WORK_TAG = "article_work";
private static final int dayInMill = 86400000;
private static final int minDelay = 960000;//16 min - Min interval for WorkManager
public static void scheduleReminder2(Context context) {
if(!isWorkScheduled2(context)) { // check if my work is not already scheduled
scheduleWork2(context); // schedule my work
}
}
public static void scheduleWork2(Context context) {
OneTimeWorkRequest.Builder myBuilder =
new OneTimeWorkRequest.Builder(ArticleWorker.class)
.setInitialDelay(calculateDelay(), TimeUnit.MILLISECONDS)
.addTag(ARTICLE_WORK_TAG)
.setConstraints(new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build());
OneTimeWorkRequest myRequest = myBuilder.build();
WorkManager.getInstance(context)
.enqueue(myRequest);
}
private static boolean isWorkScheduled2(Context context) {
WorkManager instance = WorkManager.getInstance(context);
ListenableFuture<List<WorkInfo>> statuses = instance.getWorkInfosByTag(ReminderUtil.ARTICLE_WORK_TAG);
try {
boolean running = false;
List<WorkInfo> workInfoList = statuses.get();
for (WorkInfo workInfo : workInfoList) {
WorkInfo.State state = workInfo.getState();
running = state == WorkInfo.State.RUNNING | state == WorkInfo.State.ENQUEUED;
}
return running;
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
return false;
}
}
private static long calculateDelay() {
Calendar now = Calendar.getInstance();
Calendar future = Calendar.getInstance();
// When to run the job
int hourOfTheDay = 8;
future.set(Calendar.HOUR_OF_DAY, hourOfTheDay);
future.set(Calendar.MINUTE, 0);
future.set(Calendar.SECOND, 0);
long diff = future.getTimeInMillis() - now.getTimeInMillis();
if (diff > minDelay) {
return diff;
}
else
return diff + dayInMill;
}
}
And Worker class
public class ArticleWorker extends Worker {
private Context mContext;
public ArticleWorker(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
mContext = context;
}
#NonNull
#Override
public Result doWork() {
//downloading new article date list
List<ArticleLight> recentArticleLightList = QueryUtils.getArticlesLight(ArticleUtils.articleUrl);
//sorting by Date
Collections.sort(recentArticleLightList, (o1, o2) -> o2.getDate().compareTo(o1.getDate()));
Date newestDate = recentArticleLightList.get(0).getDate();
String articleText = recentArticleLightList.get(0).getTitle();
//compare newestDate with last saved sate
SharedPreferences prefs = mContext.getSharedPreferences("MyPref", Context.MODE_PRIVATE);
long savedDateLong = prefs.getLong("date", 0);
savedDateLong = savedDateLong - 604800000;//todo this is a notification test
Date savedDate = new Date(savedDateLong);
Log.i("myTAG", "WORKER");
if (newestDate.compareTo(savedDate) > 0) {
//we have new article!
NotificationUtil.createNotification(mContext, articleText);
Log.i("myTAG", "NOTIFICATION");
}
ReminderUtil.scheduleWork2(mContext);//todo test of oneTime Work
return Result.success();
}
}
First thing make sure your PeriodicWorkRequest is not created multiple times and you can check with WorkManager.enqueueUniquePeriodicWork method.
PeriodicWorkRequest.Builder myWorkBuilder =
new PeriodicWorkRequest.Builder(ArticleWorker.class, 120, MINUTES, 10,
MINUTES);
PeriodicWorkRequest myWork = myWorkBuilder.build();
WorkManager.getInstance()
.enqueueUniquePeriodicWork("jobTag", ExistingPeriodicWorkPolicy.KEEP, myWork);
This method allows you to enqueue a uniquely-named PeriodicWorkRequest, where only one PeriodicWorkRequest of a particular name can be active at a time. For example, you may only want one sync operation to be active. If there is one pending, you can choose to let it run or replace it with your new work.
Related
What I am doing :
I need to download a file of 100 mb from background
I am using work manager with retrofit to achieve this
I am launching retrofit from work manager
It is a one time download (once I download the file. I don't need the service running in background to download again)
What is Happening :
If I keep the app in the foreground I am successfully able to
download the file
But say once after launching the worker thread I close the app. I
notice file don't get download in background.
Question: How to make sure all 100 mb file is downloaded in background till completion
In activity I am launching:
final WorkManager mWorkManager = WorkManager.getInstance(context);
final OneTimeWorkRequest mRequest = new OneTimeWorkRequest.Builder(DictionaryWorker.class)
.setConstraints(new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(true)
.setRequiresStorageNotLow(true)
.build())
.addTag(DICTIONARY_WORKER_TAG)
.build();
mWorkManager.enqueue(mRequest);
In the worker class:
public class DictionaryWorker extends Worker {
private final String CURRENT_SCREEN = DictionaryWorker.this.getClass().getSimpleName();
private static final String WORK_RESULT = "work_result";
private Context context;
private NetworkComponent networkComponent;
public DictionaryWorker(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
this.context = context;
}
#NonNull
#Override
public Result doWork() {
initCnxNetworkConnection(context);
Data outputData = new Data.Builder().putString(WORK_RESULT, "Jobs Finished").build();
return Result.failure(outputData);
}
private RandomUsersApi getNetworkService(Context context) {
if(networkComponent==null){
networkComponent = DaggerNetworkComponent.builder()
.contextModule(new ContextModule(context))
.networkModule(new NetworkModule())
.okHttpClientModule(new OkHttpClientModule())
.build();
}
return networkComponent.getService();
}
/********************************************************** RETROFIT *************************************************/
private void initCnxNetworkConnection(final Context context) {
try{
Call<ResponseBody> call = getNetworkService(context).downloadDictionary();
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
//File is downloaded here and written to storage
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Timber.e(CURRENT_SCREEN, "error");
}
});
}catch (Exception ex){
incompleteDownload();
Timber.e(CURRENT_SCREEN, "error%s", ex);
}
}
/********************************************************** RETROFIT *************************************************/
}
I am just trying for below scenario
Guaranteed execution:– The WorkManager will make sure to start the execution of background tasks under different conditions, even if we come out of the app.
I am looking for a solution for uploading data to Firebase without having the user wait for the data to upload, so that the user can use the app in offline mode.
Let's suppose that the app is about places. In this app, the user can upload an image and an object containing address, city, state, country, latitude, longitude, description, etc. Let's say a big POJO.
Firebase Realtime Database and Firebase Firestore can wait for (I do not know for how long) a stable internet connection to send the data. But Firebase Storage do not have this feature.
So I've found WorkManager. It seemed to solve the problem, but I had to serialize my POJO into small primitive variable types in order to send the POJO to Worker class.
The result I want to achieve is:
1) upload image to Firebase Storage
2) download URL of the image
3) send the POJO to Firebase Firestore with the ImageUrl in it.
QUESTIONS
1) Is WorkManager best suited for this kind of purpose?
2) How many times can an user trigger this background job without causing any issue to the app in offline mode?
3) How to propperly send the POJO to the Worker class?
Here is what I've done so far:
Get pushKey for the new place, start the background job and keep navigating through activities:
savePlaceData.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
DocumentReference docRef = DatabaseRouter.getPlaceCollectionRef().document();
String key = docRef.getId();
uploadPlaceDataInBackground(key)
Intent intent = new Intent(PlaceActivity.this, OtherActivity.class);
startActivity(intent);
}
});
Set the request for the background job:
private void uploadPlaceDataInBackground(String placeKey) {
// TESTING WORKMANAGER FOR UPLOADING IMAGES TO FIREBASE STORAGE
// Create a Constraints object that defines when the task should run
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build();
// Passing data to the worker class
Data.Builder uploadBuilder = new Data.Builder();
uploadBuilder.putString("image_uri", placeImageUri.toString());
uploadBuilder.putString("image_pushkey", placeKey);
Data ImageUriInputData = uploadBuilder.build();
// ...then create a OneTimeWorkRequest that uses those constraints
OneTimeWorkRequest uploadWorkRequest = new OneTimeWorkRequest
.Builder(UploadImageWorker.class)
.setConstraints(constraints)
.setInputData(ImageUriInputData)
.build();
OneTimeWorkRequest downloadWorkRequest = new OneTimeWorkRequest
.Builder(DownloadImageUrlWorker.class)
.setConstraints(constraints)
.build();
// Converting placeObject into Map
Data.Builder uploadPlaceBuilder = new Data.Builder();
Map<String, Object> placeMap = convertPlaceObjectIntoMap();
uploadPlaceBuilder.putAll(placeMap);
Data placeInfoInputData = uploadPlaceBuilder.build();
OneTimeWorkRequest uploadPlaceWorkRequest = new OneTimeWorkRequest
.Builder(UploadPlaceWorker.class)
.setConstraints(constraints)
.setInputData(placeInfoInputData)
.build();
// Execute and Manage the background service
WorkManager workManager = WorkManager.getInstance(getActivity());
workManager.beginWith(uploadWorkRequest)
.then(downloadWorkRequest)
.then(uploadPlaceWorkRequest)
.enqueue();
}
Below are the Worker classes:
public class UploadImageWorker extends Worker {
public UploadImageWorker(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
#NonNull
#Override
public Result doWork() {
String imageUriInput = getInputData().getString("image_uri");
String imagePushKey = getInputData().getString("image_pushkey");
final Result[] result = {Result.retry()};
CountDownLatch countDownLatch = new CountDownLatch(1);
StorageReference storageRef = DatabaseRouter.getPlaceStorageRef(imagePushKey).child(imagePushKey+".jpg");
storageRef.putFile(Uri.parse(imageUriInput)).addOnCompleteListener(new OnCompleteListener<UploadTask.TaskSnapshot>() {
#Override
public void onComplete(#NonNull Task<UploadTask.TaskSnapshot> task) {
if (task.isSuccessful()) {
result[0] = Result.success(getInputData());
} else {
Log.i(TAG, "onComplete: image NOT uploaded - RETRYING");
result[0] = Result.retry();
}
countDownLatch.countDown();
}
});
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
return result[0];
}
}
public class DownloadImageUrlWorker extends Worker {
public DownloadImageUrlWorker(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
#NonNull
#Override
public Result doWork() {
String imageUriInput = getInputData().getString("image_uri");
String imagePushKey = getInputData().getString("image_pushkey");
final Result[] result = {Result.retry()};
CountDownLatch countDownLatch = new CountDownLatch(1);
StorageReference storageRef = DatabaseRouter.getPlaceStorageRef(imagePushKey).child(imagePushKey+".jpg");
storageRef.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
String imageUrl = uri.toString();
Data.Builder outputBuilder = new Data.Builder();
outputBuilder.putString("image_url", imageUrl);
outputBuilder.putString("image_pushkey", imagePushKey);
Data outputData = outputBuilder.build();
result[0] = Result.success(outputData);
countDownLatch.countDown();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.i(TAG, "onFailure: imageUrl NOT downloaded - RETRYING");
result[0] = Result.retry();
countDownLatch.countDown();
}
});
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
return result[0];
}
}
public class UploadPlaceWorker extends Worker {
public UploadPlaceWorker(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
#NonNull
#Override
public Result doWork() {
String imageUrl = getInputData().getString("image_url");
String imagePushKey = getInputData().getString("image_pushkey");
Map<String, Object> placeObject = getInputData().getKeyValueMap();
PlaceModel placeModel = convertMapIntoPlaceObject(placeObject, imageUrl, imagePushKey);
final Result[] result = {Result.retry()};
CountDownLatch countDownLatch = new CountDownLatch(1);
DocumentReference docRef = DatabaseRouter.getPlaceCollectionRef().document(imagePushKey);
docRef.set(placeModel).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
result[0] = Result.success();
} else {
Log.i(TAG, "onComplete: place NOT uploaded - RETRYING");
result[0] = Result.retry();
}
countDownLatch.countDown();
}
});
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
return result[0];
}
private PlaceModel convertMapIntoPlaceObject(Map<String, Object> placeMap, String imageUrl, String placeKey) {
PlaceModel place = new PlaceModel();
place.setAddress(placeMap.get("a").toString());
place.setCity(placeMap.get("b").toString());
place.setCountry(placeMap.get("c").toString());
place.setDistrict(placeMap.get("d").toString());
place.setG(placeMap.get("e").toString());
place.setId(placeMap.get("f").toString());
place.setImage(imageUrl);
place.setKey(placeKey);
GeoPoint geoPoint = new GeoPoint((Double) placeMap.get("h"), (Double) placeMap.get("i"));
place.setL(geoPoint);
place.setDescription(placeMap.get("j").toString());
return place;
}
}
I appreciate any help!
I want to sync Room database periodically. I am using work manager to do it. I have created a periodic work request and I want to send a table with setInputData(TABLE HERE..). I want to know if I am I doing it right. And if right, how can I send the table to work manager periodically? If wrong, please help me with a suitable solution.
Here is my code:
//schedule recurring task only once
//Fragment
if(!SessionManager.getBoolenFromPreferences(getActivity(),REFRESH_ATTENDANCE)){
attendanceViewModel.setupPeriodicRefreshWork();
SessionManager.putBoolenInPreferences(getActivity(), true, REFRESH_ATTENDANCE);
}
//view model
public void setupPeriodicRefreshWork() {
AttendanceScheduler.refreshWork();
}
//Scheduler
public static void refreshWork() {
//define constraints
Constraints myConstraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build();
//How to Set Data Here ?
Data source = new Data.Builder()
.put(HERE)
.build();
PeriodicWorkRequest refreshWork =
new PeriodicWorkRequest.Builder(AttendanceWorker.class, 1, TimeUnit.HOURS)
.setConstraints(myConstraints)
.setInputData(source)
.build();
WorkManager.getInstance().enqueue(refreshWork);
}
Here is my worker code:
public class AttendanceWorker extends Worker {
private Executor executor;
private static final String TAG = "AttendanceWorker";
public AttendanceWorker(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
executor = Executors.newSingleThreadExecutor();
}
#SuppressLint("CheckResult")
#NonNull
#Override
public Result doWork() {
Context context = getApplicationContext();
AttendanceDao attendanceDao = DatabaseInstance.getInstance(context).attendanceDao();
Attendance attendance = attendanceDao.getAttendanceDetailsForSync();
NetworkUtils.getAPIService().saveAttendanceDetails(attendance).compose(RxUtils.applySchedulers())
.subscribe(
(AttendanceResponse attendanceResponse) -> executor.execute(() ->
{
if (attendanceResponse != null) {
if (attendanceResponse.getResult().equals("1")) {
Log.d(TAG, "Attendance Synced!");
}
}
}),
Throwable::printStackTrace
);
return Result.success();
}
}
I am doing an app where I click the START button and get current time, and hitting STOP gets the time again. I´ve been using system time without any errors, recently I changed it to server time, which is in an Asynctask, but the app is unstable since, slowed down and exits without error messages, but on faster connections it can process. Any idea why? This is my code:
class getDST2 extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... arg0) {
try {
TimeTCPClient client = new TimeTCPClient();
try {
client.setDefaultTimeout(60000);
client.connect("time.nist.gov");
simpledate = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
do_casu = simpledate.format(client.getDate());
} finally {
client.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(Void result) {
getDSTdone = true;
}
}
Also doing a graphic timer of the current time since Start was clicked so I need to get server time every second inside a handler.. code:
handler.post(r = new Runnable() {
public void run() {
hasStartedtt2 = true;
calendar = Calendar.getInstance();
simpledate = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
new getDST2().execute(); // THIS IS THE ASynctask, returns the "do_casu" String
zaciatok_hour = zaciatok.substring(11, 13);
zaciatok_minute = zaciatok.substring(14, 16);
koniec_hour = do_casu.substring(11, 13);
koniec_minute = do_casu.substring(14, 16);
zaciatok_sekundy = zaciatok.substring(17, 19);
koniec_sekundy = do_casu.substring(17, 19);
final_hour = ((Integer.parseInt(koniec_hour) - Integer.parseInt(zaciatok_hour)));
final_minute = Integer.parseInt(koniec_minute) - Integer.parseInt(zaciatok_minute);
final_seconds = Integer.parseInt(koniec_sekundy) - Integer.parseInt(zaciatok_sekundy) - 1;
}
});
Handler is called every second.
ServerTimeThread sth = new ServerTimeThread();
sth.start();
from_time = simpledate.format(sth.time);
when you call 'sth.time',the thread just start and is still in progress.
'time' is remain uninitialized,it is init at end of thread
So when accessing 'time',it is null absolutely.
2 way for AsyncTask
Blocking operation:
public class NTPDateTask extends AsyncTask<Void,Void,Date> {
#Override
protected Date doInBackground(Void... voids) {
Date date=fetchYourDate();
//fetch your date here
return date;
}
}
then call
Date result = new NTPDateTask().execute().get();
Non-Blocking operation(Callback pattern):
public class NTPDateTask extends AsyncTask<Void,Void,Date> {
#Override
protected Date doInBackground(Void... voids) {
Date date = fetchYourDate();
//fetch your date here
return date;
}
#Override
protected void onPostExecute(Date date) {
//this is 'callback'
//do the thing you want when task finish
//onPostExecute is called when doInBackground finished,and it runs on UIThread
}
}
then
new NTPDateTask().execute();
EDIT:
class TCPTimeDisplayWorker implements Runnable {
static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
boolean isActive = true;
private Handler targetHandler;
public TCPTimeDisplayWorker(Handler targetHandler) {
//pass the handler ref here
this.targetHandler = targetHandler;
}
#Override
public void run() {
while (isActive) {
long startTime = System.currentTimeMillis();
Date date = fetchDateFromTCPClient();
//fetch Server Date here
String currentDateText = simpleDateFormat.format(date);
targetHandler.sendMessage(Message.obtain(targetHandler, 0, currentDateText));
long endTime = System.currentTimeMillis();
long lapse = endTime - startTime;
if (lapse < 1000) {
try {
Thread.sleep(1000 - lapse);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
Handler:
// Non-static inner class will hold outer-class reference,may risk in memory leak
static class MainHandler extends Handler {
private WeakReference<TextView> textViewWeakReference;
// declare as WeakRef to avoid memory leak
public MainHandler(Looper looper, WeakReference<TextView> textViewWeakReference) {
super(looper);
this.textViewWeakReference = textViewWeakReference;
}
#Override
public void handleMessage(Message msg) {
if (textViewWeakReference.get() != null) {
//handle the message from message queue here
String text = (String) msg.obj;
textViewWeakReference.get().setText(text);
}
}
}
then
// must use the same handler to send msg from Background thread and
// handle at Main Thread
// a handler create on a thread will bound to that thread
mainHandler = new MainHandler(Looper.getMainLooper(), new WeakReference<>(mTextViewSystemTime));
new Thread(new TCPTimeDisplayWorker(mainHandler)).start();
btw,CamelCase is the common naming convention in Java.
Hope these are helpful.
I have a job service that i want to excecute for every three hours, I have made the jobservice class but I don't know how to excecute it every three hours.
here is my Jobservice class
public class CleanupJobService extends JobService {
private static final String TAG = CleanupJobService.class.getSimpleName();
#Override
public boolean onStartJob(JobParameters params) {
Log.d(TAG, "Cleanup job started");
new CleanupTask().execute(params);
//Work is not yet complete
return true;
}
#Override
public boolean onStopJob(JobParameters params) {
//No need to reschedule any jobs
return false;
}
/* Handle access to the database on a background thread */
private class CleanupTask extends AsyncTask<JobParameters, Void, JobParameters> {
#Override
protected JobParameters doInBackground(JobParameters... params) {
String where = String.format("%s = ?", DatabaseContract.TaskColumns.IS_COMPLETE);
String[] args = {"1"};
int count = getContentResolver().delete(DatabaseContract.CONTENT_URI, where, args);
Log.d(TAG, "Cleaned up " + count + " completed tasks");
return params[0];
}
#Override
protected void onPostExecute(JobParameters jobParameters) {
//Notify that the work is now done
jobFinished(jobParameters, false);
}
}
}
and registered it on Manifest
<service
android:name=".data.CleanupJobService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="true"/>
Any idea to resolve this ? Thanks!
solved, I am using jobInfo class to solve this, the code should look like this
ComponentName jobService = new ComponentName(getContext(), CleanupJobService.class);
JobInfo task = new JobInfo.Builder(CLEANUP_JOB_ID, jobService)
.setPeriodic(jobInterval)
.setPersisted(true)
.build();
jobInterval is the predefined time that we want the service to excecute, the type is Long and have a millis format.