首页 > 解决方案 > 将查询参数传递给 Android 应用程序中的 LiveData/Viewmodel

问题描述

由于我是编写 Android 应用程序的新手,因此我遵循了有关如何使用 Android 架构组件和 Firebase 来实现 MVVM(使用 LiveData、ViewModel 等)的教程。

我遵循的教程可以在这里找到:

我现在只剩下我认为是 MVVM 的一个不错的实现,但我无法理解我应该如何将查询参数传递给它。现在我需要硬编码要检索的文档的 ID:

public class AlarmDAO {

    private FirebaseFirestore firebaseFirestore = FirebaseFirestore.getInstance();

    public AlarmLiveData getFirestoreLiveData() {
        DocumentReference documentReference = firebaseFirestore.collection(Collection.ALARMS.name).document("5RxJNuNyhDJlz49wpBkw");

        return new AlarmLiveData(documentReference);
    }

}

然后由扩展类调用ViewModel

public class AlarmViewModel extends ViewModel {

    private AlarmDAO DAO = new AlarmDAO();
    private AlarmLiveData liveData = null;

    public LiveData<Alarm> getAlarmLiveData() {
        liveData = DAO.getFirestoreLiveData();
        return liveData;
    }

    public LiveData<Alarm> getAlarm() {
        return liveData.alarm;
    }

}

然后我在我的活动中观察到这些数据:

model.getAlarmLiveData().observe(this, Observable -> {});
model.getAlarm().observe(this, alarm -> {
   if (alarm != null) {
      alarmTextView.setText(alarm.getTest());
   else {
      Log.d(TAG, "Waiting for data");
   }
});

我的问题是我没有看到查询特定警报的方法。例如model.getAlarm("someId"). 我的印象是它应该在 DAO 和/或 ViewModel 中完成,但我不知道怎么做。我不明白的另一件事是为什么我需要同时观察model.getAlarmLiveData()model.getAlarm()的活动,因为只使用一个是行不通的。这两个问题的答案很可能很简单,但到目前为止我还没有弄清楚。

为了完整起见:Alarm除了两个字符串的 getter 和 setter 之外,该类什么都没有,并且AlarmLiveData该类在下面。

public class AlarmLiveData extends LiveData<Alarm> implements EventListener<DocumentSnapshot> {

    private static final String TAG = AlarmLiveData.class.getSimpleName();

    private Alarm alarmTemp = new Alarm();
    private DocumentReference documentReference;
    private ListenerRegistration listenerRegistration = () -> {};

    public MutableLiveData<Alarm> alarm = new MutableLiveData<>();

    public AlarmLiveData(DocumentReference documentReference) {
        this.documentReference = documentReference;
    }

    @Override
    protected void onActive() {
        listenerRegistration = documentReference.addSnapshotListener(this);
        super.onActive();
    }

    @Override
    protected void onInactive() {
        listenerRegistration.remove();
        super.onInactive();
    }


    @Override
    public void onEvent(@Nullable DocumentSnapshot documentSnapshot, @Nullable FirebaseFirestoreException e) {
        if (documentSnapshot != null && documentSnapshot.exists()) {
            alarmTemp = new Alarm();
            alarmTemp.setId(documentSnapshot.getId());
            alarmTemp.setTest(documentSnapshot.get("test").toString());
            alarm.setValue(alarmTemp);
        } else {
            Log.d(TAG, "ERROR");
        }
    }
}

感谢阅读,期待答案!

标签: javaandroidandroid-mvvm

解决方案


您必须同时使用两者的原因model.getAlarmLiveData()似乎model.getAlarm()是您的 AlarmLiveData 类扩展了 LiveData 但为包含的 MutableLiveData 成员变量设置了一个值,而不是设置其自己的类值。

在您的 AlarmLiveData 类中:

// Comment out/Remove your 'public MutableLiveData<alarm> alarm' member variable from the top.
// You're going to want to set the value of the AlarmLiveData class itself instead.

// ...

// Then inside of your onEvent callback
@Override
public void onEvent(@Nullable DocumentSnapshot documentSnapshot, @Nullable FirebaseFirestoreException e) {
    if (documentSnapshot != null && documentSnapshot.exists()) {
        alarmTemp = new Alarm();
        alarmTemp.setId(documentSnapshot.getId());
        alarmTemp.setTest(documentSnapshot.get("test").toString());
        
        // Set the value for the AlarmLiveData class directly
        setValue(alarmTemp);
    } else {
        Log.d(TAG, "ERROR");
    }
}

我不确定您为什么要创建 DAO 类,我很可能会将该代码直接移动到 AlarmViewModel 类中。但是,如果您不想删除当前的 DAO 类,可以通过以下方式更改它:

// Pass in the document id you want to create a document reference for
public AlarmLiveData getFirestoreLiveData(String documentId) {
    DocumentReference documentReference = firebaseFirestore.collection(Collection.ALARMS.name).document(documentId);

    return new AlarmLiveData(documentReference);
}

您的 AlarmViewModel 类看起来像这样:

public class AlarmViewModel extends ViewModel {

    private AlarmDAO DAO = new AlarmDAO();
    private AlarmLiveData liveData = null;

    // Make sure to take in the document id so you can create the corresponding LiveData
    public LiveData<Alarm> getAlarmLiveData(String documentId) {
        // Only create a new LiveData instance if the current one is null.
        // This is helpful if you intend to use this as a Shared ViewModel.
        if(liveData == null){
            liveData = DAO.getFirestoreLiveData(documentId);
        }
        
        return liveData;
    }
}

最后,在您的活动中:

// Pass in the document id and observe the ViewModel
model.getAlarmLiveData("MY_DOCUMENT_ID").observe(this, alarm -> {
   if (alarm != null) {
      alarmTextView.setText(alarm.getTest());
   }else{
      Log.d(TAG, "Waiting for data");
   }
});

推荐阅读