Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/209.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 如何从工人类获取ViewModel? 我的应用程序中有一个名为MainActivity的Activity_Android_Android Architecture Components_Android Viewmodel_Android Workmanager - Fatal编程技术网

Android 如何从工人类获取ViewModel? 我的应用程序中有一个名为MainActivity的Activity

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

main活动与OnCreate方法中的
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替换为上下文