问题
I want to replace the job scheduling aspect of my existing data syncing system with the new JetPack WorkManager (link to codelabs) component (in a sandbox branch of the app). My existing system works well but some of the new features in WorkManager
would come in handy (e.g. chaining).
My current system uses a shared LiveData
to communicate the progress from a job in progress to any UI element (RecyclerView
in my case) observing on it (I'm actually SwitchMapping in the ViewModel
into a list of SyncItem
s)
data class SyncItem(
val title: String,
private var _progress: Int,
var total: Int) : BaseObservable() {
var progress: Int
@Bindable get() = _progress
set(value) {
_progress = value
notifyPropertyChanged(BR.progress)
}
}
The new WorkManager
component has several methods (getStatusById
, getStatusesByTag
, etc.) that can be used to retrieve a LiveData with one or more WorkStatus
es, but these only report a course-grained status (running, success, failed, cancelled).
What is the recommended way of communicating progress (e.g. '546/1234 items downloaded') to the UI? The setOutputData
/getOutputData
pair seems to be used more to communicate between Worker
s (which I need when chaining) than with the UI.
Attached is a screenshot of what it looks like (in a [test] version of my app using my old method) when a user opens the sync status page (2 items completed, rest in progress).
In the final product the user will be able to cancel any jobs in progress and re-issue once-off work requests. Normally the jobs will be fired off by PeriodicWorkRequest
.
回答1:
The best way to do it is to write intermediate progress to your own data store and expose a LiveData<>
. We are considering adding this feature in a future alpha.
回答2:
Progress report is now available natively. For now just on alpha release.
implementation 'androidx.work:work-runtime:2.3.0-alpha01'
Report progress on Worker:
public class FooWorker extends Worker {
public FooWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
@NonNull
@Override
public Result doWork() {
try {
setProgressAsync(new Data.Builder().putInt("progress", 0).build());
Thread.sleep(1000);
setProgressAsync(new Data.Builder().putInt("progress", 50).build());
Thread.sleep(1000);
setProgressAsync(new Data.Builder().putInt("progress", 100).build());
return Result.success();
} catch (InterruptedException e) {
e.printStackTrace();
return Result.failure();
}
}
}
Observe progress from Worker:
public class FooActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_foo);
OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(FooWorker.class)
.build();
WorkManager.getInstance(this).beginUniqueWork(
"test", ExistingWorkPolicy.REPLACE, request).enqueue();
WorkManager.getInstance(this).getWorkInfosForUniqueWorkLiveData("test").observe(this, new Observer<List<WorkInfo>>() {
@Override
public void onChanged(List<WorkInfo> workInfos) {
if (workInfos.size() > 0) {
WorkInfo info = workInfos.get(0);
int progress = info.getProgress().getInt("progress", -1);
//Do something with progress variable
}
}
});
}
}
ListenableWorkers can now set progress via the setProgressAsync() API. Also added a corresponding suspend-ing setProgress API in CoroutineWorker and a setProgress in RxWorker which returns a Single. With these new APIs Workers can convey progress information via WorkInfo which has a corresponding getProgress API. (b/79481554)
See WorkManager Version 2.3.0-alpha01
来源:https://stackoverflow.com/questions/50542223/showing-detailed-progress-for-running-workmanager-workers