Skip to content

Snappy1

  • Home
  • Android
  • What
  • How
  • Is
  • Can
  • Does
  • Do
  • Why
  • Are
  • Who
  • Toggle search form

[FIXED] android – WorkManager job doesn’t get rescheduled or it doesn’t fire after some time

Posted on November 11, 2022 By

Solution 1 :

Here you can learn how to use work manager.

Create a new project and add WorkManager dependency in app/buid.gradle file

implementation "android.arch.work:work-runtime:1.0.0"

Create a base class of Worker:-

package com.wave.workmanagerexample;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.v4.app.NotificationCompat;
import androidx.work.Data;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
/**
 * Created on : Mar 26, 2019
 * Author     : AndroidWave
 */
public class NotificationWorker extends Worker {
    private static final String WORK_RESULT = "work_result";
    public NotificationWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
    }
    @NonNull
    @Override
    public Result doWork() {
        Data taskData = getInputData();
        String taskDataString = taskData.getString(MainActivity.MESSAGE_STATUS);
        showNotification("WorkManager", taskDataString != null ? taskDataString : "Message has been Sent");
        Data outputData = new Data.Builder().putString(WORK_RESULT, "Jobs Finished").build();
        return Result.success(outputData);
    }
    private void showNotification(String task, String desc) {
        NotificationManager manager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
        String channelId = "task_channel";
        String channelName = "task_name";
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new
                    NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT);
            manager.createNotificationChannel(channel);
        }
        NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(), channelId)
                .setContentTitle(task)
                .setContentText(desc)
                .setSmallIcon(R.mipmap.ic_launcher);
        manager.notify(1, builder.build());
    }
}

Create WorkRequest:-

Let’s move to MainActivity and create a WorkRequest to execute the work that we just created. Now first we will create WorkManager. This work manager will enqueue and manage our work request.

 WorkManager mWorkManager = WorkManager.getInstance();

Now we will create OneTimeWorkRequest, because I want to create a task that will be executed just once.

OneTimeWorkRequest mRequest = new OneTimeWorkRequest.Builder(NotificationWorker.class).build();

Using this code we built work request, that will be executed one time only

Enqueue the request with WorkManager:-

btnSend.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mWorkManager.enqueue(mRequest);
        }
    });

Fetch the particular task status:-

mWorkManager.getWorkInfoByIdLiveData(mRequest.getId()).observe(this, new Observer<WorkInfo>() {
        @Override
        public void onChanged(@Nullable WorkInfo workInfo) {
            if (workInfo != null) {
                WorkInfo.State state = workInfo.getState();
                tvStatus.append(state.toString() + "n");
            }
        }
    });

Finally, MainActivity looks like this.

package com.wave.workmanagerexample;
import android.arch.lifecycle.Observer;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkInfo;
import androidx.work.WorkManager;
public class MainActivity extends AppCompatActivity {
    public static final String MESSAGE_STATUS = "message_status";
    TextView tvStatus;
    Button btnSend;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvStatus = findViewById(R.id.tvStatus);
        btnSend = findViewById(R.id.btnSend);
        final WorkManager mWorkManager = WorkManager.getInstance();
        final OneTimeWorkRequest mRequest = new OneTimeWorkRequest.Builder(NotificationWorker.class).build();
        btnSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mWorkManager.enqueue(mRequest);
            }
        });
        mWorkManager.getWorkInfoByIdLiveData(mRequest.getId()).observe(this, new Observer<WorkInfo>() {
            @Override
            public void onChanged(@Nullable WorkInfo workInfo) {
                if (workInfo != null) {
                    WorkInfo.State state = workInfo.getState();
                    tvStatus.append(state.toString() + "n");
                }
            }
        });
    }
}

Problem :

I´ve been facing a issue with WorkManager when reescheduling jobs. Currently, I´ve found that at some point after launching a request with Okhttp and raising an error on AuthInterceptor it gets stuck and no other job gets launched.

READ  [FIXED] android studio - I'm having some trouble with retrofit and sending some data to the server
Powered by Inline Related Posts

This is the JobOrganizer class that manages the first steps of the work planing. It chains the first queue of jobs. You will see more jobs that are not pasted here but the main difference is that the first chained job goes without WiFi network constraints and the others does.

object JobOrganizer {

    const val WORK_INTERVAL: Long = 20
    const val SCH_DATA_UPDATE_WORK_RESCHEDULE = "scheduled_data_update_work_reschedule"
    const val SCH_DATA_UPDATE_WORK = "scheduled_data_update_work"

    private val schDataUpdateJob: OneTimeWorkRequest
        get() = OneTimeWorkRequestBuilder<SCHDataUpdateJob>()
                .addTag(SCH_DATA_UPDATE_WORK)
                .setConstraints(wifiConstraint)
                .build()

    val wifiConstraint: Constraints
        get() = Constraints.Builder()
                .setRequiredNetworkType(NetworkType.UNMETERED)
                .setRequiresDeviceIdle(false)
                .setRequiresBatteryNotLow(false)
                .setRequiresCharging(false)
                .setRequiresStorageNotLow(false)
                .build()

    fun getWorkInfos(context: Context, tag: String): LiveData<List<WorkInfo>> {
        val workManager = WorkManager.getInstance(context)
        return workManager.getWorkInfosByTagLiveData(tag)
    }

    private fun clearWorks(workManager: WorkManager) {
        workManager.pruneWork()
    }

    private fun cancelSCHJobs(context: Context) {
        val workManager = WorkManager.getInstance(context)
        workManager.cancelAllWorkByTag(SCH_DATA_UPDATE_WORK )
        clearWorks(workManager)
    }

    fun scheduleJobs(context: Context) {
        cancelSCHJobs(context)
        WorkManager.getInstance(context)
                .beginWith(schTypesDownloadJob)
                .then(schDownloadJob)
                .then(schDataUpdateJob)
                .then(schDataUploadJob)
                .then(schCleanupJob)
                .enqueue()
        FirebaseAnalytics.getInstance(context).logEvent(AnalyticsEvents.Sync.SYNC_SCH_CONFIGURE_FORM_CLEANUP, Bundle())
    }
}

The AuthInterceptor class

class AuthInterceptor(private val context: Context?) : Interceptor {

    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {

        val originalRequest = chain.request()

        if (context == null) {
            return chain.proceed(originalRequest)
        }

        val auth = AuthRepository(context).getAuth()
        if (auth.isNullOrEmpty()) {
            return chain.proceed(originalRequest)
        }

        val version = String.format(
                "%s: %s (build %s)",
                BuildConfig.FLAVOR,
                BuildConfig.VERSION_NAME,
                BuildConfig.VERSION_CODE
        )

        val compressedRequest = originalRequest.newBuilder()
                .header("Authorization", String.format("Bearer %s", auth[0].token))
                .header("mobile-app-version", version)
                .build()
        return chain.proceed(compressedRequest)
    }

}

The Update Job that reeschedules itself with a 30 min delay. The main try / catch is for the AuthInterceptor errors.

class SCHDataUpdateJob(var context : Context, params : WorkerParameters) : Worker(context, params) {

    override fun doWork(): Result {
        FirebaseAnalytics.getInstance(context).logEvent(AnalyticsEvents.Sync.SYNC_SCH_UPDATE_START, Bundle())
        var success = UPDElementTypesJob(context).doWork()
        if (!success) {
            FirebaseAnalytics.getInstance(context).logEvent(AnalyticsEvents.Sync.SYNC_UPD_ELEMENTTYPES_ERROR, Bundle())
            Log.e("SYNC", "SCHDataUpdateJob UPDElementTypesJob error")
        }
        FirebaseAnalytics.getInstance(context).logEvent(AnalyticsEvents.Sync.SYNC_SCH_UPDATE_FINISH, Bundle())

        val dataUpdateWorkRequest = OneTimeWorkRequestBuilder<SCHDataUpdateJob>()
                .setInitialDelay(JobOrganizer.WORK_INTERVAL, TimeUnit.MINUTES)
                .addTag(JobOrganizer.SCH_DATA_UPDATE_WORK)
                .setConstraints(JobOrganizer.wifiConstraint)
                .build()

        WorkManager.getInstance(applicationContext)
                .enqueue(dataUpdateWorkRequest)

        Log.e("SYNC", "SCHDataUpdateJob finished")
        return Result.success()
    }
}

This is the fragment that calls scheduleJobs().

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
    super.onCreateView(inflater, container, savedInstanceState)

    mainView = inflater.inflate(R.layout.fragment_draft_list, container, false)

    sync = mainView!!.findViewById(R.id.sync)

    sync.onClick {
        mFirebaseAnalytics!!.logEvent(AnalyticsEvents.UPDATE_BUTTON_CLICKED, Bundle())
        if (!ConnectionUtils.isConnectedToWifi(activity!!.applicationContext)) {
            showConnectivityDialog()
        } else {
            sync.visibility = View.GONE
            doAsync {
                JobOrganizer.scheduleJobs(context!!)
            }
        }
    }

    if (forceDownload) {
        JobOrganizer.scheduleJobs(context!!)
    }

    return mainView!!
}

At some point the this last job doens’t get scheduled or doesn’t run. Any clue?

READ  [FIXED] java - Error is occuring at mMap.setMapStyle(GoogleMap.MAP_TYPE_NORMAL); , Why?
Powered by Inline Related Posts

Thanks.

Comments

Comment posted by Harry Timothy

Where and how do you call

Comment posted by reixa

scheduleJobs() gets called just after the login to start the sync proccess, inside a Fragment. You can also call scheduleJobs() by clicking on the update button of that same fragment. Both of them are declared on onCreateView.

Comment posted by Harry Timothy

I think I know the answer, but there is one last condition I need you to verify: if you set a breakpoint at

Comment posted by reixa

The first time they get called, both of them. The jobs get fired but at some point they stop being reescheduled. SCHUpdateJob gets itself reescheduled when it succeed.

Comment posted by Furkan Yurdakul

Also please make sure you are not calling

Android Tags:android, android-workmanager, okhttp, retrofit2.6

Post navigation

Previous Post: [FIXED] java – MVVM with Room and LiveData – How to get List from LiveData
Next Post: [FIXED] android – Xamarin.Forms.Droid Resource, Ambiguous Terms/ Build Action’s Randomly Changing Missing Resources

Related Posts

[FIXED] javascript – Javascipt not working in Samsung Internet Browser Android
[FIXED] java – Room DAO fails to retrieve data from Database Android
[FIXED] localization – Android : How to dynamically change Locale for application level resources? Android
[FIXED] android – Import python module in flutter using starflut Android
[FIXED] How to get external sdcard path in android programming? Android
[FIXED] android – RxAndroidBle read and then write to a characteristic Android

Archives

  • March 2023
  • February 2023
  • January 2023
  • December 2022
  • November 2022
  • October 2022
  • September 2022

Categories

  • ¿Cómo
  • ¿Cuál
  • ¿Cuándo
  • ¿Cuántas
  • ¿Cuánto
  • ¿Qué
  • Android
  • Are
  • At
  • C'est
  • Can
  • Comment
  • Did
  • Do
  • Does
  • Est-ce
  • Est-il
  • For
  • Has
  • Hat
  • How
  • In
  • Is
  • Ist
  • Kann
  • Où
  • Pourquoi
  • Quand
  • Quel
  • Quelle
  • Quelles
  • Quels
  • Qui
  • Should
  • Sind
  • Sollte
  • Uncategorized
  • Wann
  • Warum
  • Was
  • Welche
  • Welchen
  • Welcher
  • Welches
  • Were
  • What
  • What's
  • When
  • Where
  • Which
  • Who
  • Who's
  • Why
  • Wie
  • Will
  • Wird
  • Wo
  • Woher
  • you can create a selvedge edge: You can make the edges of garter stitch more smooth by slipping the first stitch of every row.2022-02-04
  • you really only need to know two patterns: garter stitch

Recent Posts

  • What are the main features of Islamic education?
  • Is the Jeep 4xe worth it?
  • How does the ringer work on cast iron?
  • What is the biggest size interior door?
  • Is blue raspberry an original Jolly Rancher flavor?

Recent Comments

No comments to show.

Copyright © 2023 Snappy1.

Powered by PressBook Grid Dark theme