无法从片段中的 ViewModel 观察 LiveData

Can't Observe LiveData from ViewModel in Fragment

我的 ViewPager 中有一个 RecyclerView Fragment。此 RecyclerView 显示从服务器获取的数据。它通常可以工作,但我无法使用 ViewModelLiveData 实现相同的功能,因为 livedata.observe 方法在 livedata 被调用时没有被调用从 ViewModel.

更改

这是我的 MonthlyOrderViewModel.java class

的源代码
public class MonthlyOrderViewModel extends AndroidViewModel {

private Retrofit retrofit;
private RetrofitServices retrofitServices;
private MutableLiveData<MonthlyOrderHistory> monthlyOrderHistoryMutableLiveData = new MutableLiveData<>();

public MonthlyOrderViewModel(@NonNull Application application) {
    super(application);
    retrofit = RetrofitFactory.getRetrofit();
    retrofitServices = retrofit.create(RetrofitServices.class);
}

public MutableLiveData<MonthlyOrderHistory> getMonthlyOrderHistoryMutableLiveData() {
    return monthlyOrderHistoryMutableLiveData;
}
public void fetchMonthlyOrders() {
    Call<MonthlyOrderHistory> call = retrofitServices.getAllMonthlyOrderHistory(IpharmaApplication.getInstance().getLoggedInUser().getId());
    call.enqueue(new Callback<MonthlyOrderHistory>() {
        @Override
        public void onResponse(Call<MonthlyOrderHistory> call, Response<MonthlyOrderHistory> response) {

            MonthlyOrderHistory monthlyOrderHistory = response.body();
            if(monthlyOrderHistory.getStatus().equalsIgnoreCase("success")) {

                List<UserOrder> userOrders = monthlyOrderHistory.getOrders().getUserOrder();
                if(userOrders != null && userOrders.size() != 0) {
                    DefaultScheduler.INSTANCE.execute(() -> {
                        monthlyOrderHistoryMutableLiveData.postValue(monthlyOrderHistory);
                        return Unit.INSTANCE;
                    });
                }
            }
        }

        @Override
        public void onFailure(Call<MonthlyOrderHistory> call, Throwable t) {

            t.printStackTrace();
        }
    });
}

}

DefaultScheduler 是一个 Scheduler,默认情况下处理 AsyncScheduler 中的操作。 这是我的 Scheduler.kt class

的源代码

interface Scheduler {

    fun execute(task: () -> Unit)

    fun postToMainThread(task: () -> Unit)

    fun postDelayedToMainThread(delay: Long, task: () -> Unit)
}

//A shim [Scheduler] that by default handles operations in the [AsyncScheduler].
object DefaultScheduler : Scheduler {

    private var delegate: Scheduler = AsyncScheduler

    //Sets the new delegate scheduler, null to revert to the default async one.
    fun setDelegate(newDelegate: Scheduler?) {
        delegate = newDelegate ?: AsyncScheduler
    }

    override fun execute(task: () -> Unit) {
        delegate.execute(task)
    }

    override fun postToMainThread(task: () -> Unit) {
        delegate.postToMainThread(task)
    }

    override fun postDelayedToMainThread(delay: Long, task: () -> Unit) {
        delegate.postDelayedToMainThread(delay, task)
    }
}

//Runs tasks in a [ExecutorService] with a fixed thread of pools
internal object AsyncScheduler : Scheduler {

    private val executorService: ExecutorService = Executors.newFixedThreadPool(NUMBER_OF_THREADS)

    override fun execute(task: () -> Unit) {
        executorService.execute(task)
    }

    override fun postToMainThread(task: () -> Unit) {
        if (isMainThread()) {
            task()
        } else {
            val mainThreadHandler = Handler(Looper.getMainLooper())
            mainThreadHandler.post(task)
        }
    }

    private fun isMainThread(): Boolean {
        return Looper.getMainLooper().thread === Thread.currentThread()
    }

    override fun postDelayedToMainThread(delay: Long, task: () -> Unit) {
        val mainThreadHandler = Handler(Looper.getMainLooper())
        mainThreadHandler.postDelayed(task, delay)
    }
}

//Runs tasks synchronously.
object SyncScheduler : Scheduler {
    private val postDelayedTasks = mutableListOf<() -> Unit>()

    override fun execute(task: () -> Unit) {
        task()
    }
    override fun postToMainThread(task: () -> Unit) {
        task()
    }
    override fun postDelayedToMainThread(delay: Long, task: () -> Unit) {
        postDelayedTasks.add(task)
    }
    fun runAllScheduledPostDelayedTasks() {
        val tasks = postDelayedTasks.toList()
        clearScheduledPostdelayedTasks()
        for (task in tasks) {
            task()
        }
    }
    fun clearScheduledPostdelayedTasks() {
        postDelayedTasks.clear()
    }
}

最后,我尝试使用以下方法观察片段 onCreateView 方法的变化:

MonthlyOrderViewModel monthlyOrderViewModel = new MonthlyOrderViewModel(getActivity().getApplication());

monthlyOrderViewModel.getMonthlyOrderHistoryMutableLiveData().observe(this, monthlyOrderHistory -> {

    monthlyOrderRecyclerView = view.findViewById(R.id.monthlyOrderRecyclerView);

    monthlyOrderRecyclerViewAdapter = new OrderHistoryRecyclerViewAdapter(getContext(), monthlyOrderHistory.getOrders().getUserOrder());

    monthlyOrderRecyclerViewAdapter.notifyDataSetChanged();

    monthlyOrderRecyclerView.setAdapter(monthlyOrderRecyclerViewAdapter);       

    monthlyOrderRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));

});

我尝试调试了一下,发现retrofit取数据没有问题。但是当我尝试在我的片段中使用它们时,observe 方法永远不会被调用。

请建议我如何解决这个问题?任何帮助将不胜感激。

您不应该使用 new 实例化您的 ViewModel。你必须这样做:

MonthlyOrderViewModel monthlyOrderViewModel = ViewModelProviders.of(this).get(MonthlyOrderViewModel.class);

如果您确定 postValue 正在您的 ViewModel 中执行,那么我认为此更改应该可以使其正常工作。还有一件事:每次观察到的 LiveData 通知您更改时,您不应该做所有这些。我会将下一行移动到 observe()

之前
monthlyOrderRecyclerView = view.findViewById(R.id.monthlyOrderRecyclerView);

monthlyOrderRecyclerViewAdapter = new OrderHistoryRecyclerViewAdapter(getContext(), monthlyOrderHistory.getOrders().getUserOrder());

monthlyOrderRecyclerView.setAdapter(monthlyOrderRecyclerViewAdapter);       

monthlyOrderRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));

更新

正如 Fahim 在评论中确认的那样,问题在于创建了相同 ViewModel 的多个实例。如果您需要共享 ViewModel 的相同实例,请确保传递 Fragment/Activity 的引用,即该 ViewModel 的 "owner"。例如,如果 MyActivity 有一个 MainActivityViewModel 并且它包含一个名为 MyFragment 的子 Fragment,那么如果该 Fragment 想要获得对其父 ViewModel 的引用,则必须在以下方式:

MainActivityViewModel mainActivityVM = ViewModelProviders
                                            .of(getActivity())
                                            .get(MainActivityViewModel.class);