有什么方法可以非持久地运行WorkManager的请求?

时间:2019-04-03 11:33:49

标签: android-workmanager

我已切换到WorkManager并在几乎所有情况下使用它。通过请求ID返回LiveData的方法对于UI绑定非常方便。

我有一个任务要登录到远程服务器。因此,我想继续使用WorkManagers API来完成此任务,但不需要总的数据库级持久性。我只需要在应用程序生命周期(例如,方向更改期间)中跟踪任务,并且无需将凭据发布到服务数据库。

是否有任何方法可以使我的后台任务以WorkManager的方式但没有持久性地排队并跟踪,仅用于运行进程?

好的,我基于WorkManager的类实现了自己的小型WorkManager,但是很难支持。

static class ThreadWorkManager extends TinyWorkManager {

        static final String TAG = ThreadWorkManager.class.getSimpleName();

        final ExecutorService executor = Executors.newFixedThreadPool(10);
        final Executor uiExecutor = Utils::uiPost;
        final HashMap<UUID, WorkData> workDatum = new HashMap<>();
        final WeakHashMap<MutableLiveData<WorkInfo>, UUID> liveIdDatum = new WeakHashMap<>();
        final WeakHashMap<MutableLiveData<WorkInfo>, String> liveTagDatum = new WeakHashMap<>();

        static WorkInfo fromWorkData(UUID id, WorkData workData) {
            return workData != null ? new WorkInfo(id, workData.spec.state, workData.spec.output, workData.tagList) : null;
        }

        static class WorkData {
            final ListenableWorker worker;
            final WorkSpec spec;
            final Set<String> tags;
            final List<String> tagList;
            long time = System.currentTimeMillis();
            Runnable startLater;

            WorkData(ListenableWorker worker, WorkSpec spec) {
                this.worker = worker;
                this.spec = spec;
                this.tags = worker.getTags();
                this.tagList = new ArrayList<>(tags);
            }
        }

        void onWorkChanged(UUID id) {
            //if (BuildConfig.DEBUG && Thread.currentThread() != ui.getLooper().getThread())
            //  throw new AssertionError();

            WorkData workData = workDatum.get(id);
            if (workData == null) return;

            workData.time = System.currentTimeMillis();

            WorkInfo workInfo = fromWorkData(id, workData);

            //TODO remove finished workdata and id livedata

            while (true) {
                try {
                    for (Map.Entry<MutableLiveData<WorkInfo>, UUID> entry : liveIdDatum.entrySet())
                        if (entry.getValue().equals(id))
                            entry.getKey().setValue(workInfo);
                    break;
                } catch (ConcurrentModificationException e) {
                    Log.w(TAG, "concurrent 1");
                }
            }

            while (true) {
                try {
                    for (Map.Entry<MutableLiveData<WorkInfo>, String> entry : liveTagDatum.entrySet())
                        if (workData.tags.contains(entry.getValue()))
                            entry.getKey().setValue(workInfo);
                    break;
                } catch (ConcurrentModificationException e) {
                    Log.w(TAG, "concurrent 2");
                }
            }
        }

        void scheduleWork(UUID id, WorkData workData, long delay) {
            workData.spec.state = WorkInfo.State.ENQUEUED;

            onWorkChanged(id);

            uiPost(workData.startLater = () -> {
                workData.startLater = null;

                workData.spec.state = WorkInfo.State.RUNNING;

                onWorkChanged(id);

                ListenableFuture<ListenableWorker.Result> future = workData.worker.startWork();
                future.addListener(new WorkerListener(id, future), uiExecutor);
            }, delay);
        }

        @Override
        public void enqueue(WorkRequest workRequest) {
            //executor.submit(new WorkUnit(workRequest));

            try {
                Class<? extends ListenableWorker> workerClass = (Class<? extends ListenableWorker>) Class.forName(workRequest.getWorkSpec().workerClassName);
                Class[] types = {Context.class, WorkerParameters.class};
                Constructor constructor = workerClass.getConstructor(types);

                UUID id = workRequest.getId();
                WorkSpec workSpec = workRequest.getWorkSpec();

                ListenableWorker worker = (ListenableWorker) constructor.newInstance(appContext, new WorkerParameters(
                        id,
                        workSpec.input,
                        workRequest.getTags(),
                        null,
                        workSpec.runAttemptCount,
                        executor,
                        null,
                        null));

                WorkData workData = new WorkData(worker, workRequest.getWorkSpec());
                workDatum.put(worker.getId(), workData);

                if (workSpec.initialDelay > 0) {
                    scheduleWork(id, workData, workSpec.initialDelay);
                } else {
                    workSpec.state = WorkInfo.State.RUNNING;

                    onWorkChanged(id);

                    ListenableFuture<ListenableWorker.Result> future = worker.startWork();
                    future.addListener(new WorkerListener(worker.getId(), future), uiExecutor);
                }
            } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | InvocationTargetException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }

        class WorkerListener implements Runnable {

            private final UUID id;
            private final ListenableFuture<ListenableWorker.Result> future;

            WorkerListener(UUID id, ListenableFuture<ListenableWorker.Result> future) {
                this.id = id;
                this.future = future;
            }

            @Override
            public void run() {
                WorkData workData = workDatum.get(id);
                if (workData == null) return;

                try {
                    ListenableWorker.Result r = future.get();
                    if (r == null || r instanceof ListenableWorker.Result.Failure) {
                        workData.spec.state = WorkInfo.State.FAILED;
                        if (r != null)
                            workData.spec.output = ((ListenableWorker.Result.Failure) r).getOutputData();

                        onWorkChanged(workData.worker.getId());
                    } else if (r instanceof ListenableWorker.Result.Success) {
                        workData.spec.state = WorkInfo.State.SUCCEEDED;
                        workData.spec.output = ((ListenableWorker.Result.Success) r).getOutputData();

                        onWorkChanged(id);

                        if(workData.spec.isPeriodic())
                            scheduleWork(id, workData, workData.spec.intervalDuration);
                    } else if (r instanceof ListenableWorker.Result.Retry) {
                        workData.spec.state = WorkInfo.State.ENQUEUED;

                        onWorkChanged(id);

                        //TODO spec.backoffPolicy
                        scheduleWork(id, workData, workData.spec.backoffDelayDuration);
                    }

                    Log.d(TAG, workData.worker.getClass().getSimpleName() + " " + id + " " + workData.spec.state);
                } catch (ExecutionException | InterruptedException e) {
                    Log.e(TAG, workData.worker.getClass().getSimpleName() + " " + id + " no future");
                }
            }
        }

        @Override
        public WorkInfo getWorkInfo(String tag) {
            WorkData tagWorkData = null;
            for (WorkData workData : workDatum.values())
                if (workData.tags.contains(tag) && (tagWorkData == null || tagWorkData.time < workData.time))
                    tagWorkData = workData;

            return tagWorkData != null ? fromWorkData(UUID.fromString(tagWorkData.spec.id), tagWorkData) : null;
        }

        @Override
        public LiveData<WorkInfo> getWorkInfoLiveData(UUID id) {
            if (BuildConfig.DEBUG && Thread.currentThread() != ui.getLooper().getThread())
                throw new AssertionError();

            MutableLiveData<WorkInfo> liveData = null;

            while (true) {
                try {
                    for (Map.Entry<MutableLiveData<WorkInfo>, UUID> entry : liveIdDatum.entrySet())
                        if (entry.getValue().equals(id)) {
                            liveData = entry.getKey();

                            break;
                        }
                    break;
                } catch (ConcurrentModificationException e) {
                    Log.w(TAG, "concurrent 3");
                }
            }

            if (liveData == null) {
                liveIdDatum.put(liveData = new MutableLiveData<>(), id);

                WorkInfo workInfo = fromWorkData(id, workDatum.get(id));
                if (workInfo != null)
                    liveData.setValue(workInfo);
            }

            return liveData;
        }

        @Override
        public LiveData<WorkInfo> getWorkInfoLiveData(String tag) {
            if (BuildConfig.DEBUG && Thread.currentThread() != ui.getLooper().getThread())
                throw new AssertionError();

            MutableLiveData<WorkInfo> liveData = null;
            while (true) {
                try {
                    for (Map.Entry<MutableLiveData<WorkInfo>, String> entry : liveTagDatum.entrySet())
                        if (entry.getValue().equals(tag)) {
                            liveData = entry.getKey();

                            break;
                        }
                    break;
                } catch (ConcurrentModificationException e) {
                    Log.w(TAG, "concurrent 4");
                }
            }

            if (liveData == null) {
                liveTagDatum.put(liveData = new MutableLiveData<>(), tag);

                WorkInfo workInfo = getWorkInfo(tag);
                if (workInfo != null)
                    liveData.setValue(workInfo);
            }

            return liveData;
        }

        @Override
        public void cancelWork(UUID id) {
            WorkData workData = workDatum.get(id);
            if (workData != null && !workData.spec.state.isFinished()) {
                if (workData.startLater != null) {
                    uiRemove(workData.startLater);
                    workData.startLater = null;
                }

                workData.worker.stop();

                workData.spec.state = WorkInfo.State.CANCELLED;

                onWorkChanged(id);
            }
        }

        @Override
        public void cancelWork(String tag) {
            for (WorkData workData : workDatum.values())
                if (workData.tags.contains(tag))
                    cancelWork(UUID.fromString(workData.spec.id));
        }
    }

1 个答案:

答案 0 :(得分:0)

如果不需要保留任务,则不应使用WorkManager。您应该改为根据《后台处理指南》找到其他解决方案:https://developer.android.com/guide/background/

相关问题