如何保证新独特的工作将运行,无论已经运行的工作如何
我想安排工作以将用户数据从我的应用程序同步到服务器。当用户将新信息保存在应用程序中时,该工作应运行。
fun scheduleWork(context: Context) {
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
val request = OneTimeWorkRequest.Builder(ObservationSyncWorker::class.java)
.setConstraints(constraints)
.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
.build()
WorkManager
.getInstance(context)
.beginUniqueWork("syncData", ExistingWorkPolicy.APPEND_OR_REPLACE, request)
.enqueue()
}
工作示例:
override suspend fun doWork(): Result {
// get unsync'ed data from database
val data = repository.getLocalData()
// Start network request to sync data
val response = repository.sync(data)
if (response.isSuccessful) {
// Network request complete, save server response
repository.save(response.body())
}
// Done
return Result.success()
}
在先前的数据完成之前,用户有机会保存新数据。文档工作策略有些限制,并希望确保我正在使用正确的策略。
工作人员:
public enum ExistingWorkPolicy {
/**
* If there is existing pending (uncompleted) work with the same unique name, cancel and delete
* it. Then, insert the newly-specified work.
*/
REPLACE,
/**
* If there is existing pending (uncompleted) work with the same unique name, do nothing.
* Otherwise, insert the newly-specified work.
*/
KEEP,
/**
* If there is existing pending (uncompleted) work with the same unique name, append the
* newly-specified work as a child of all the leaves of that work sequence. Otherwise, insert
* the newly-specified work as the start of a new sequence.
* <br/>
* <b>Note:</b> When using APPEND with failed or cancelled prerequisites, newly enqueued work
* will also be marked as failed or cancelled respectively. Use
* {@link ExistingWorkPolicy#APPEND_OR_REPLACE} to create a new chain of work.
*/
APPEND,
/**
* If there is existing pending (uncompleted) work with the same unique name, append the
* newly-specified work as the child of all the leaves of that work sequence. Otherwise, insert
* the newly-specified work as the start of a new sequence.
* <br/>
* <b>Note:</b> If there are failed or cancelled prerequisites, these prerequisites are
* <i>dropped</i> and the newly-specified work is the start of a new sequence.
*/
APPEND_OR_REPLACE,
}
使用替换: 由于我同步数据的工作将捕获所有数据,因此我可以使用替换,这将取消第一个工作请求,并安排第二个工作请求。第二个工作请求应从取消的第一项工作中获取UNSYNC的数据。这里的好处可能是在离线时安排多个工作请求(请参阅在线约束),不会堆叠孩子以同步。
使用 keep : 如果安排了现有的同步工作,这将无济于事。如果离线和用户多次保存数据,则此功能很好。数据的每一个保存都将导致未安排新的工作。但是,如果现有工作仍在流程或同步,则如果用户保存并计划了新工作,我认为新的工作请求将被忽略。对于我的用例来说,这似乎是一个不好的选择。
使用:附加: 如果以前的同步工作失败,则使用 Append 将导致未安排新的工作。 由于我希望将所有同步工作都安排,无论以前的工作如何,我认为这是一个糟糕的选择。
使用 append_or_replace : 这是一个可行的选项,因为如果可以,则计划新作品的工作是可以的。此选项还将允许先前计划的工作完成,然后再安排更多工作。如果用户数据正在同步过程中并且保存新数据,则可以很好地工作。但是,在离线时保存多次会导致多个工作被附加。这将是浪费的,因为建立连接时,第一个工作请求将同步所有数据,而其余的工作任务无关紧要。
对于我的用例,我正在考虑替换或 append_or_replace 。
使用替换,由于可以取消工作,因此运行同步有可能在有效的服务器响应之间取消并将该响应保存到我的数据库之间。
使用 append_or_replace ,不会取消任何工作。但是,在某些情况下,额外的工作可能没有任何同步。我的工人确实检查了它是否有效,所以这可能是无害的。看来这是更安全的选择。
I would like to schedule work to sync user data from my application to a server. The work should run when the user saves new information within the application.
fun scheduleWork(context: Context) {
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
val request = OneTimeWorkRequest.Builder(ObservationSyncWorker::class.java)
.setConstraints(constraints)
.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
.build()
WorkManager
.getInstance(context)
.beginUniqueWork("syncData", ExistingWorkPolicy.APPEND_OR_REPLACE, request)
.enqueue()
}
Example of work:
override suspend fun doWork(): Result {
// get unsync'ed data from database
val data = repository.getLocalData()
// Start network request to sync data
val response = repository.sync(data)
if (response.isSuccessful) {
// Network request complete, save server response
repository.save(response.body())
}
// Done
return Result.success()
}
The is a chance that the user will save new data before the previous data has finished. The documentation work policy is a bit limited and want to make sure I am using the correct policy.
WorkPolicy:
public enum ExistingWorkPolicy {
/**
* If there is existing pending (uncompleted) work with the same unique name, cancel and delete
* it. Then, insert the newly-specified work.
*/
REPLACE,
/**
* If there is existing pending (uncompleted) work with the same unique name, do nothing.
* Otherwise, insert the newly-specified work.
*/
KEEP,
/**
* If there is existing pending (uncompleted) work with the same unique name, append the
* newly-specified work as a child of all the leaves of that work sequence. Otherwise, insert
* the newly-specified work as the start of a new sequence.
* <br/>
* <b>Note:</b> When using APPEND with failed or cancelled prerequisites, newly enqueued work
* will also be marked as failed or cancelled respectively. Use
* {@link ExistingWorkPolicy#APPEND_OR_REPLACE} to create a new chain of work.
*/
APPEND,
/**
* If there is existing pending (uncompleted) work with the same unique name, append the
* newly-specified work as the child of all the leaves of that work sequence. Otherwise, insert
* the newly-specified work as the start of a new sequence.
* <br/>
* <b>Note:</b> If there are failed or cancelled prerequisites, these prerequisites are
* <i>dropped</i> and the newly-specified work is the start of a new sequence.
*/
APPEND_OR_REPLACE,
}
Using REPLACE:
Since my work to synchronize data will catch all data I could use REPLACE, which will cancel the first work request, and schedule the second work request. This second work request should catch unsync'ed data from the first work that was cancelled. The benefit here might be that scheduling multiple work requests when offline (see online constraint), won't stack up children to sync.
Using KEEP:
This will do nothing if existing work to sync is scheduled. This work great if offline and the user saves data multiple times. Each save of data will result in no new work being scheduled. However in the case that existing work is still in the process or sync'ing, if the user saves and new work is scheduled, I think that new work request will be ignore. This seems like a bad option for my use case.
Using: APPEND:
If previous sync work failed, using APPEND will result in new work not being scheduled.
Since I want all sync work to be scheduled regardless of previous work, I think this is a bad option.
Using APPEND_OR_REPLACE:
This is a viable option since scheduling new work if previous work failed is ok. This option will also allow previously scheduled work to complete before more work is scheduled. This works great if the users data is in the process of sync'ing and they save new data. However saving multiple times while offline will cause multiple work to be appended. This will be wasteful as when a connection is established the first work request will sync all data, leaving the remaining work tasks with nothing to do.
For my use case I am considering REPLACE or APPEND_OR_REPLACE.
With REPLACE since work can be cancelled there is a chance that a running sync could cancel in between a valid server response and saving that response to my database.
With APPEND_OR_REPLACE no work will be cancelled. However extra work could run in some cases with nothing to sync. My worker does check if it has work to do, so this might be harmless. It seems this is the safer option.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这不是一种干净的方法,但是您可以使用append_or_replace尝试这样的尝试:
https://developer.android.com/topic/libraries/architecture/workmanager/workmanager/how-to/states-tace/states-and-bobservation#one-time time_work_states
https://developer.android.com/reference/androidx/work/workinfo.state#isfined()“ rel =” nofollow noreferrer“> https://developer..android.com/reference.com/reference.com/reference/reference/androidx/androidx/androidx/work/work/workinfo.state.state #IsFined()
It is not a clean approach, but you can try like this with APPEND_OR_REPLACE:
https://developer.android.com/topic/libraries/architecture/workmanager/how-to/states-and-observation#one-time_work_states
https://developer.android.com/reference/androidx/work/WorkInfo.State#isFinished()