Android 如何从工人类获取ViewModel? 我的应用程序中有一个名为MainActivity的Activity
main活动与OnCreate方法中的Android 如何从工人类获取ViewModel? 我的应用程序中有一个名为MainActivity的Activity,android,android-architecture-components,android-viewmodel,android-workmanager,Android,Android Architecture Components,Android Viewmodel,Android Workmanager,main活动与OnCreate方法中的ViewModel相关联 ... val someViewModel = ViewModelProviders.of(this).get(SomeViewModel::class.java) ... 我和工人一起做一些背景工作 val someWork=OneTimeWorkRequestBuilder().build() WorkManager.getInstance().beginUniqueWork(“SOMEWORK”,ExistingWorkP
ViewModel
相关联
...
val someViewModel = ViewModelProviders.of(this).get(SomeViewModel::class.java)
...
工人一起做一些背景工作
val someWork=OneTimeWorkRequestBuilder().build()
WorkManager.getInstance().beginUniqueWork(“SOMEWORK”,ExistingWorkPolicy.REPLACE,captivePortalWork).enqueue()
工作者
循环10次,每次只需睡眠一秒钟。。。所以我们有10秒的背景工作。
我想更新ViewModel
以显示后台工作的进度,并每次更新UI
A) 我可以从Main活动访问视图模型并观察工作者
,但我只能在进度成功或失败时更新视图模型
。。。这意味着当工作完成0%或100%时,我可以显示进度
B) 如果我可以从Worker类访问ViewModel,我可以随时更新ViewModel。但我不知道怎么。。。此方法在Worker类中不起作用
val someWork=ViewModelProviders.of(this).get(SomeViewModel::class.java)
如何从工人
班级获得视图模型
您不能为此使用
ViewModel
。您需要使用自己的房间数据库,并将LiveData
公开到您的用户界面以显示进度。您必须将Worker
输出数据的值分配给ViewModel
,并在活动中观察到该数据,如下所示:
工人代码:
public class MyWorker extends Worker {
public static final String MY_KEY_DATA_FROM_WORKER = "MY_KEY_DATA_FROM_WORKER";
public MyWorker(@NonNull Context appContext, @NonNull WorkerParameters workerParams) {
super(appContext, workerParams);
}
@NonNull
@Override
public Worker.Result doWork() {
//here do http or database requests
String result = "my needed result";
if (result != null) {
setOutputData(new Data.Builder()
.putString(MY_KEY_DATA_FROM_WORKER, result)
.build());
return Worker.Result.SUCCESS;
}
return Result.FAILURE;
}
}
ViewModel的代码:
public class MyActivityModel extends ViewModel {
private final MutableLiveData<String> myLiveData = new MutableLiveData<String>();
public void loadDataFromWorker(LifecycleOwner lifecycleOwner) {
OneTimeWorkRequest myWorkerReq = new OneTimeWorkRequest.Builder(MyWorker.class)
.build();
WorkManager mWorkManager = WorkManager.getInstance();
mWorkManager
.beginWith(myWorkerReq)
.enqueue();
mWorkManager.getStatusByIdLiveData(myWorkerReq.getId()).observe(lifecycleOwner, new Observer<WorkStatus>() {
@Override
public void onChanged(WorkStatus workStatus) {
if (workStatus.getState().isFinished()) {
// here you asign data to ViewModel
Data workOutputData = workStatus.getOutputData();
myLiveData.setValue(workOutputData.getString(MyWorker .MY_KEY_DATA_FROM_WORKER));
}
}
});
}
public MutableLiveData<String> getData() {
return myLiveData;
}
}
公共类MyActivityModel扩展了ViewModel{
private final MutableLiveData myLiveData=新的MutableLiveData();
public void loadDataFromWorker(LifecycleOwner LifecycleOwner){
OneTimeWorkRequest myWorkerReq=新的OneTimeWorkRequest.Builder(MyWorker.class)
.build();
WorkManager mWorkManager=WorkManager.getInstance();
工作经理
.beginWith(myWorkerReq)
.enqueue();
mWorkManager.getStatusByIdLiveData(myWorkerReq.getId()).observe(lifecycleOwner,new Observator()){
@凌驾
更改后的公共无效(WorkStatus WorkStatus){
if(workStatus.getState().isFinished()){
//在这里,您可以将数据指定给ViewModel
数据workOutputData=workStatus.getOutputData();
设置值(workOutputData.getString(MyWorker.MY_KEY_DATA_FROM_WORKER));
}
}
});
}
public MutableLiveData getData(){
返回myLiveData;
}
}
活动代码:
//...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
//declare model and start loading data in Worker
MyActivityModel model = ViewModelProviders.of(this).get(MyActivityModel.class);
model.loadDataFromWorker(this);
//observe data from model
model.getData().observe(this, new Observer<String>() {
@Override
public void onChanged(String str) {
//here you get new String value or null if Work failed
}
});
}
//...
/。。。
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.my_活动);
//声明模型并开始在Worker中加载数据
MyActivityModel=ViewModelProviders.of(this.get)(MyActivityModel.class);
model.loadDataFromWorker(此);
//从模型中观察数据
model.getData().observe(这个,新的观察者(){
@凌驾
更改后的公共void(字符串str){
//在这里,如果工作失败,您将获得新的字符串值或null
}
});
}
//...
来自非常好的谷歌文档的两个附加信息
a) 如果您来到这里是因为没有viewmodelscope.launch无法运行任务,请查看Android“”文档
b) 这里的问题可能可以通过“.”解决。简而言之,您不想将ViewModel
暴露给WorkManager
或Worker
类,而是将百分比暴露给ViewModel
WorkManager 2.3.1+增加了对设置和观察中间进度的支持
对于使用ListenableWorker或Worker的Java开发人员,setProgressAsync()API返回ListenableFuture;更新进度是异步的,因为更新过程涉及将进度信息存储在数据库中。在Kotlin中,可以使用CoroutineWorker对象的setProgress()扩展函数来更新进度信息
对于Kotlin,使用CoroutineWorker
和以下内容:
companion object {
const val Progress = "Progress"
private const val delayDuration = 1L
}
override suspend fun doWork(): Result {
val firstUpdate = workDataOf(Progress to 0)
val lastUpdate = workDataOf(Progress to 100)
setProgress(firstUpdate)
delay(delayDuration)
setProgress(lastUpdate)
return Result.success()
}
在您的视图模型中
,您可以这样观察您的进度:
WorkManager.getInstance(applicationContext)
// requestId is the WorkRequest id
.getWorkInfoByIdLiveData(requestId)
.observe(observer, Observer { workInfo: WorkInfo? ->
if (workInfo != null) {
val progress = workInfo.progress
val value = progress.getInt(Progress, 0)
// Do something with progress information
}
})
WorkContinuation.combine(workForSyncingFlights).also {
it.enqueue()
it.workInfosLiveData.asFlow().conflate().collect { listOfWorkInfo ->
if (listOfWorkInfo.isNullOrEmpty()) return@collect
listOfWorkInfo.forEach { workInfo ->
if (workInfo.state.isFinished) {
val finished = listOfWorkInfo.filter { info -> info.state.isFinished }.size
val totalPercent = finished.toDouble().div(listOfWorkInfo.size.toDouble()) * 100
}
}
}
如果您使用的是WorkContinuation
,并且希望获得总体百分比,我发现最简单的方法是像这样使用workinfo-slivedata
:
WorkManager.getInstance(applicationContext)
// requestId is the WorkRequest id
.getWorkInfoByIdLiveData(requestId)
.observe(observer, Observer { workInfo: WorkInfo? ->
if (workInfo != null) {
val progress = workInfo.progress
val value = progress.getInt(Progress, 0)
// Do something with progress information
}
})
WorkContinuation.combine(workForSyncingFlights).also {
it.enqueue()
it.workInfosLiveData.asFlow().conflate().collect { listOfWorkInfo ->
if (listOfWorkInfo.isNullOrEmpty()) return@collect
listOfWorkInfo.forEach { workInfo ->
if (workInfo.state.isFinished) {
val finished = listOfWorkInfo.filter { info -> info.state.isFinished }.size
val totalPercent = finished.toDouble().div(listOfWorkInfo.size.toDouble()) * 100
}
}
}
请格式化您的代码。我不确定这是如何正确回答的,但您不需要房间数据库来完成此操作。这是一种方法,但肯定不是显示工作类进度的最佳实践。假设您不希望从工作类向viewmodel发送字符串这样简单的数据,而是整个http响应,例如自定义对象列表。你是如何做到的?ThanksWorkManager.getInstance()现在已被弃用,请使用WorkManager.getInstance(上下文),将LifecycleOwner替换为上下文