Задание WorkManager не переносится или не запускается через некоторое время - PullRequest
2 голосов
/ 26 февраля 2020

У меня возникла проблема с WorkManager при перепланировании заданий. В настоящее время я обнаружил, что в какой-то момент после запуска запроса с Okhttp и сообщения об ошибке на AuthInterceptor он застревает, и никакое другое задание не запускается.

Это класс JobOrganizer, который управляет первыми шагами планирования работы. Это цепочка первой очереди заданий. Вы увидите больше заданий, которые здесь не вставлены, но главное отличие состоит в том, что первое связанное задание проходит без сетевых ограничений WiFi , а остальные -

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())
    }
}

Класс AuthInterceptor

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)
    }

}

Задание обновления, которое повторно планируется с задержкой в ​​30 минут. Основной try / catch предназначен для ошибок AuthInterceptor.

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()
    }
}

Это фрагмент, который вызывает 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!!
}

В какой-то момент эта последняя работа не может быть получена запланировано или не работает. Любая подсказка?

Спасибо.

1 Ответ

0 голосов
/ 06 марта 2020

Здесь вы можете узнать, как использовать диспетчер работы.

Создать новый проект и добавить зависимость WorkManager в файл app / buid.gradle

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

Создать базовый класс 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());
    }
}

Создать WorkRequest: -

Давайте перейдем к MainActivity и создадим WorkRequest для выполнения только что созданной работы. Теперь сначала мы создадим WorkManager. Этот менеджер работ будет ставить в очередь и управлять нашим рабочим запросом.

 WorkManager mWorkManager = WorkManager.getInstance();

Теперь мы создадим OneTimeWorkRequest, потому что я хочу создать задачу, которая будет выполняться только один раз.

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

Использование В этом коде мы создали рабочий запрос, который будет выполнен только один раз

Поставить запрос в очередь с помощью WorkManager: -

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");
            }
        }
    });

Наконец, MainActivity выглядит следующим образом.

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");
                }
            }
        });
    }
}
...