Android 在使用MVVM模型观察数据库更改的活动中返回LiveData时出现问题

Android 在使用MVVM模型观察数据库更改的活动中返回LiveData时出现问题,android,mvvm,android-room,android-livedata,Android,Mvvm,Android Room,Android Livedata,在我的应用程序中,我从存储库中的Room数据库(SQLite)返回LiveData,并观察应用程序活动中的数据 问题是:在活动中使用LiveData,使用MVVM模型观察数据库中的更改,并在数据更改时运行一些代码(因为观察就是这样工作的) 存储库中的方法如下所示: public LiveData<TourWithAllGeoPoints> getTourWithAllGeoPoints(long tourId, boolean mIsFirstTime) { if (!mIs

在我的应用程序中,我从存储库中的Room数据库(SQLite)返回LiveData,并观察应用程序活动中的数据

问题是:在活动中使用LiveData,使用MVVM模型观察数据库中的更改,并在数据更改时运行一些代码(因为观察就是这样工作的)

存储库中的方法如下所示:

public LiveData<TourWithAllGeoPoints> getTourWithAllGeoPoints(long tourId, boolean mIsFirstTime) {
    if (!mIsFirstTime) { 
        return tourWithAllGeoPoints;
    }
    MyTourAssistentDatabase.databaseWriteExecutor.execute(()-> {
        tourWithAllGeoPoints = toursDAO.getTourWithAllGeoPoints(tourId);  //this part finishes after reuturn
    });
    return tourWithAllGeoPoints;  //this part returns
}
但问题是,在execute()部分完成之前,该方法返回“tourWithAllGeoPoints”。这意味着它返回一个空的LiveData。或者我们在MainActivity上观察到的LiveData与我们从toursDAO获得的LiveData不同

因此,在活动中,它观察空的LiveData

我尝试的解决方案是:

1)我可以像这样在主线程中运行查询:

public LiveData<TourWithAllGeoPoints> getTourWithAllGeoPoints(long tourId, boolean mIsFirstTime) {
    if (!mIsFirstTime) { 
        return tourWithAllGeoPoints;
    }
  
    tourWithAllGeoPoints = toursDAO.getTourWithAllGeoPoints(tourId);

    return tourWithAllGeoPoints;
}
public LiveData<TourWithAllGeoPoints> getTourWithAllGeoPoints(long tourId, boolean mIsFirstTime) {
    if (!mIsFirstTime) { 
        return tourWithAllGeoPoints;
    }
    MyTourAssistentDatabase.databaseWriteExecutor.execute(()-> {
        TourWithAllGeoPoints twagp = toursDAO.getTourWithAllGeoPoints(tourId);
        tourWithAllGeoPoints.postValue(twagp)
    });
    return tourWithAllGeoPoints;
}
public LiveData<LiveData<TourWithAllGeoPoints>> getTourWithAllGeoPoints(long tourId, boolean mIsFirstTime) {
    if (!mIsFirstTime) { 
        return tourWithAllGeoPoints;
    }
    MyTourAssistentDatabase.databaseWriteExecutor.execute(()-> {
        LiveData<TourWithAllGeoPoints> twagp = toursDAO.getTourWithAllGeoPoints(tourId); //returns LiveData
        tourWithAllGeoPoints.postValue(twagp)
    });
    return tourWithAllGeoPoints;
}
public LiveData getTourWithAllGeoPoints(长巡演,布尔错误优先时间){
如果(!mIsFirstTime){
返回所有地理点的旅游;
}
tourWithAllGeoPoints=toursDAO.getTourWithAllGeoPoints(tourId);
返回所有地理点的旅游;
}
但随后它会发出警告消息,提示不要在主线程上运行对Room数据库的查询,因为这可能需要很长时间

2)或者我可以让toursDAO.getTourWithAllGeoPoints(tourId)返回TourWithAllGeoPoints对象而不是LiveData,并将其放入LiveDataobject,如下所示:

public LiveData<TourWithAllGeoPoints> getTourWithAllGeoPoints(long tourId, boolean mIsFirstTime) {
    if (!mIsFirstTime) { 
        return tourWithAllGeoPoints;
    }
  
    tourWithAllGeoPoints = toursDAO.getTourWithAllGeoPoints(tourId);

    return tourWithAllGeoPoints;
}
public LiveData<TourWithAllGeoPoints> getTourWithAllGeoPoints(long tourId, boolean mIsFirstTime) {
    if (!mIsFirstTime) { 
        return tourWithAllGeoPoints;
    }
    MyTourAssistentDatabase.databaseWriteExecutor.execute(()-> {
        TourWithAllGeoPoints twagp = toursDAO.getTourWithAllGeoPoints(tourId);
        tourWithAllGeoPoints.postValue(twagp)
    });
    return tourWithAllGeoPoints;
}
public LiveData<LiveData<TourWithAllGeoPoints>> getTourWithAllGeoPoints(long tourId, boolean mIsFirstTime) {
    if (!mIsFirstTime) { 
        return tourWithAllGeoPoints;
    }
    MyTourAssistentDatabase.databaseWriteExecutor.execute(()-> {
        LiveData<TourWithAllGeoPoints> twagp = toursDAO.getTourWithAllGeoPoints(tourId); //returns LiveData
        tourWithAllGeoPoints.postValue(twagp)
    });
    return tourWithAllGeoPoints;
}
public LiveData getTourWithAllGeoPoints(长巡演,布尔错误优先时间){
如果(!mIsFirstTime){
返回所有地理点的旅游;
}
MyTourAssistentDatabase.databaseWriteExecutor.execute(()->{
TourWithAllGeoPoints twagp=toursDAO.getTourWithAllGeoPoints(tourId);
tourWithAllGeoPoints.postValue(twagp)
});
返回所有地理点的旅游;
}
这样它就能观察到LiveData中的变化。但我无法观察数据库中所做的更改,因为它只返回一个列表。这意味着每次在数据库中进行更改时都必须运行相同的方法

3)或者我可以将LiveData放在LiveData中,也可以这样:

public LiveData<TourWithAllGeoPoints> getTourWithAllGeoPoints(long tourId, boolean mIsFirstTime) {
    if (!mIsFirstTime) { 
        return tourWithAllGeoPoints;
    }
  
    tourWithAllGeoPoints = toursDAO.getTourWithAllGeoPoints(tourId);

    return tourWithAllGeoPoints;
}
public LiveData<TourWithAllGeoPoints> getTourWithAllGeoPoints(long tourId, boolean mIsFirstTime) {
    if (!mIsFirstTime) { 
        return tourWithAllGeoPoints;
    }
    MyTourAssistentDatabase.databaseWriteExecutor.execute(()-> {
        TourWithAllGeoPoints twagp = toursDAO.getTourWithAllGeoPoints(tourId);
        tourWithAllGeoPoints.postValue(twagp)
    });
    return tourWithAllGeoPoints;
}
public LiveData<LiveData<TourWithAllGeoPoints>> getTourWithAllGeoPoints(long tourId, boolean mIsFirstTime) {
    if (!mIsFirstTime) { 
        return tourWithAllGeoPoints;
    }
    MyTourAssistentDatabase.databaseWriteExecutor.execute(()-> {
        LiveData<TourWithAllGeoPoints> twagp = toursDAO.getTourWithAllGeoPoints(tourId); //returns LiveData
        tourWithAllGeoPoints.postValue(twagp)
    });
    return tourWithAllGeoPoints;
}
public LiveData getTourWithAllGeoPoints(长巡演,布尔错误优先时间){
如果(!mIsFirstTime){
返回所有地理点的旅游;
}
MyTourAssistentDatabase.databaseWriteExecutor.execute(()->{
LiveData twagp=toursDAO.getTourWithAllGeoPoints(tourId);//返回LiveData
tourWithAllGeoPoints.postValue(twagp)
});
返回所有地理点的旅游;
}
但我不知道将LiveData放在LiveData中是否是个好主意

或其他解决方案。但我如何解决这个问题?


问题是:在活动中使用LiveData,使用MVVM模型观察数据库中的更改,并在数据更改时运行一些代码(因为这就是观察的工作方式)。

对于您描述的特定问题(即返回第一个
TourWithAllGeoPoints
而不返回任何其他内容),似乎
LiveData
不是您在这里可以使用的最合适的数据类型
LiveData
用于以下情况:正如其名称所示,基础数据是活动的,并且随时可能更改,并且每次更改时都需要观察数据。如果您只需要一个值,那么最好不要使用
LiveData
。只需将DAO方法
getTourWithAllGeoPoints
返回
TourWithAllGeoPoints
(不带
LiveData
),并从后台线程调用即可。请看一些方法来做到这一点。在这种情况下,使用Kotlin协程要容易得多,但您需要使用Kotlin(我推荐:)

但是,如果您描述的问题是一般性的(不仅仅是一次返回一个值),那么您可以使用
MediatorLiveData
来观察
LiveData
,并在每次发出新值时发布不同的(或不是)内容。请看下面的代码:

private MediatorLiveData<TourWithAllGeoPoints> mediator;

public YourRepositoryConstructor() {
    mediator = new MediatorLiveData<>();
    mediator.addSource(toursDAO.getTourWithAllGeoPoints(tourId), data -> {
        if (mediator.getValue() != null) {
            mediator.setValue(data);
        }
    });
    return mediator;
}

public LiveData<TourWithAllGeoPoints> getTourWithAllGeoPoints(long tourId, boolean mIsFirstTime) {
    return mediator;
}
私有中介livedata中介;
公共YourRepositoryConstructor(){
mediator=new MediatorLiveData();
mediator.addSource(toursDAO.getTourWithAllGeoPoints(tourId),数据->{
if(mediator.getValue()!=null){
mediator.setValue(数据);
}
});
回归调解人;
}
public LiveData getTourWithAllGeoPoints(长巡演,布尔错误优先时间){
回归调解人;
}
MediatorLiveData
观察一个(或多个)其他
LiveData
对象,并根据其他
LiveData
对象的更改发出新值。它可能会发出不同的数据类型(即,它不必是底层
LiveData
对象的同一类型),甚至根本不会发出任何东西。这一切都取决于您的
livedata
代码。具体来说,在本例中,每次
getTourWithAllGeoPoints
的结果发出新的内容时,您
MediatorLiveData
将对此作出反应,并且仅在第一次发出新的值时才发出。通过检查其值是否为
null
,它不需要变量
mIsFirstTime
(除非
null
在这种情况下是有效值)

MediatorLiveData
是一种更通用的方法,适用于您所描述的场景类型,但是如果您只需要查询一个结果,那么可能需要付出太多的努力,而您可能根本不使用
LiveData
来解决这个问题