34

Java POJO 对象

public class Section {

    @ColumnInfo(name="section_id")
    public int mSectionId;

    @ColumnInfo(name="section_name")
    public String mSectionName;

    public int getSectionId() {
        return mSectionId;
    }

    public void setSectionId(int mSectionId) {
        this.mSectionId = mSectionId;
    }

    public String getSectionName() {
        return mSectionName;
    }

    public void setSectionName(String mSectionName) {
        this.mSectionName = mSectionName;
    }
}

我的查询方法

@Query("SELECT * FROM section")
LiveData<List<Section>> getAllSections();

访问数据库

final LiveData<List<Section>> sections = mDb.sectionDAO().getAllSections();

在下一行,我正在检查sections.getValue()哪个总是给我 null,尽管我在数据库中有数据,后来我得到了onChanged()方法中的值。

sections.observe(this, new Observer<List<Section>>() {
    @Override
    public void onChanged(@Nullable List<Section> sections){

    }
});

但是当我从查询中省略 LiveData 时,我得到了预期的数据。查询方法:

@Query("SELECT * FROM section")
List<Section> getAllSections();

访问数据库:

final List<Section> sections = mDb.sectionDAO().getAllSections();
4

7 回答 7

33

在下一行,我正在检查sections.getValue(),尽管我在DataBase 中有数据,但它总是给我null,后来我在onChanged() 方法中获得了值。

这是正常行为,因为返回 LiveData 的查询是异步工作的。那一刻该值为空。

所以调用这个方法

LiveData<List<Section>> getAllSections();

你稍后会在这里得到结果

sections.observe(this, new Observer<List<Section>>() {
@Override
public void onChanged(@Nullable List<Section> sections){

}
});

来自文档:

Room 不允许访问主线程上的数据库,除非您在构建器上调用 allowMainThreadQueries(),因为它可能会长时间锁定 UI。异步查询(返回 LiveData 或 RxJava Flowable 的查询)不受此规则的约束,因为它们在需要时在后台线程上异步运行查询。

于 2017-10-31T11:18:38.460 回答
19

我通过这种方法解决了这个问题

    private MediatorLiveData<List<Section>> mSectionLive = new MediatorLiveData<>();
    .
    .
    .

    @Override
    public LiveData<List<Section>> getAllSections() {
        final LiveData<List<Section>> sections = mDb.sectionDAO().getAllSections();

        mSectionLive.addSource(sections, new Observer<List<Section>>() {
            @Override
            public void onChanged(@Nullable List<Section> sectionList) {
               if(sectionList == null || sectionList.isEmpty()) {
                  // Fetch data from API
               }else{
                  mSectionLive.removeSource(sections);
                  mSectionLive.setValue(sectionList);
               }
            }
        });
        return mSectionLive;
    }
于 2017-06-10T08:49:17.480 回答
4

LiveData 是一个异步查询,您会获得 LiveData 对象,但它可能不包含任何数据。您可以使用额外的方法等待数据被填充然后提取数据。

public static <T> T getValue(LiveData<T> liveData) throws InterruptedException {
    final Object[] objects = new Object[1];
    final CountDownLatch latch = new CountDownLatch(1);

    Observer observer = new Observer() {
        @Override
        public void onChanged(@Nullable Object o) {
            objects[0] = o;
            latch.countDown();
            liveData.removeObserver(this);
        }
    };
    liveData.observeForever(observer);
    latch.await(2, TimeUnit.SECONDS);
    return (T) objects[0];
}
于 2018-04-06T13:17:18.933 回答
3

我解决了类似的问题如下

在您的 ViewModel 类中

private LiveData<List<Section>> mSections;

@Override
public LiveData<List<Section>> getAllSections() {

    if (mSections == null) {
        mSections = mDb.sectionDAO().getAllSections();
    }

    return mSections;
}

这都是必需的。切勿更改 LiveData 的实例。

于 2017-10-13T13:07:30.117 回答
3

如果您需要在代码中从数据库同步获取数据,我建议您创建另一个不带 LiveData 的查询。

道:

@Query("SELECT COUNT(*) FROM section")
int countAllSections();

视图模型:

Integer countAllSections() {
    return new CountAllSectionsTask().execute().get();
}

private static class CountAllSectionsTask extends AsyncTask<Void, Void, Integer> {

    @Override
    protected Integer doInBackground(Void... notes) {
        return mDb.sectionDAO().countAllSections();
    }
}
于 2019-08-29T23:20:32.370 回答
2

如果sections.getValue() 为null,我必须调用api 获取数据并插入数据库

你可以在onChange方法处理这个:

sections.observe(this, new Observer<List<Section>>() {
    @Override
    public void onChanged(@Nullable List<Section> sections){
         if(sections == null || sections.size() == 0) {
             // No data in your database, call your api for data
         } else {
             // One or more items retrieved, no need to call your api for data.
         }
    }
});

但是您最好将此数据库/表初始化逻辑放到存储库类中。查看Google 的示例。请参阅DatabaseCreator类。

于 2017-06-09T13:27:24.353 回答
0

对于遇到这种情况的任何人。如果您正在调用 LiveData.getValue() 并且您始终为空。您可能忘记调用 LiveData.observe()。如果您忘记这样做,getValue() 将始终使用 List<> 数据类型特别返回 null。

于 2020-06-09T05:08:21.060 回答