如何从 Worker 类中获取 ViewModel?

Osc*_*dez 3 android android-viewmodel android-architecture-components android-workmanager

  1. 我的Activivity应用程序中有一个名为 MainActivity 的应用程序。
  2. MainActivity 与ViewModelOnCreate 方法中的a 相关联

    ...
    val someViewModel = ViewModelProviders.of(this).get(SomeViewModel::class.java)
    ...
    
    Run Code Online (Sandbox Code Playgroud)
  3. 我做了一些背景工作Workers

    val someWork = OneTimeWorkRequestBuilder<LoginWorker>().build() WorkManager.getInstance().beginUniqueWork("SOMEWORK", ExistingWorkPolicy.REPLACE, captivePortalWork).enqueue()

  4. 问题来了……worker例如,循环 10 次,每次只睡一秒钟……所以我们有 10 秒的后台工作。我想更新ViewModel以显示后台工作的进度并每次更新UI。

    A) 我可以从 MainActivity 访问 View 模型并观察worker但我只能ViewModel在进度成功或失败时更新...这意味着我可以在工作完成 0 或 100% 时显示进度。

    B) 如果我可以从 Worker 类访问 ViewModel,我可以随时更新 ViewModel。但我不知道如何......这个方法在 Worker 类中不起作用。

    val someWork = ViewModelProviders.of(this).get(SomeViewModel::class.java)

    我怎样才能ViewModelWorker课堂上获得一个?

Cho*_*ski 6

您必须将Worker输出的值分配DataViewModel,并且在您的 中观察到此数据Activity,如下所示:

工人代码:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

视图模型的代码:

 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;
    }
  }
Run Code Online (Sandbox Code Playgroud)

活动代码:

//...

  @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 

        }
    });
}

//...
Run Code Online (Sandbox Code Playgroud)


Rah*_*hul -6

ViewModel您不能为此使用 a 。您需要使用自己的房间数据库并向LiveData您的 UI 公开以显示进度。

  • 我不确定这是否是正确的答案,但您不需要房间数据库来完成此任务。这是一种方法,但肯定不是显示 Worker 类进度的最佳实践。 (6认同)