LiveData.getValue() returns null with Room

前端 未结 7 848
无人及你
无人及你 2020-12-05 13:16

Java POJO Object

public class Section {

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

    @ColumnInfo(name=\"section_name\")
    public S         


        
相关标签:
7条回答
  • 2020-12-05 13:56

    LiveData is an asynchronous query, you get the LiveData object but it might contain no data. You could use an extra method to wait for the data to be filled then extract the data.

    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];
    }
    
    0 讨论(0)
  • 2020-12-05 13:57

    if sections.getValue() is null I have to call api for data and insert in into the database

    You can handle this at onChange method:

    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.
             }
        }
    });
    

    But you should better put this Database/Table initialization logic to a repository class. Check out Google's sample. See DatabaseCreator class.

    0 讨论(0)
  • 2020-12-05 13:59

    For anyone that comes across this. If you are calling LiveData.getValue() and you are consistently getting null. It is possible that you forgot to invoke LiveData.observe(). If you forget to do so getValue() will always return null specially with List<> datatypes.

    0 讨论(0)
  • 2020-12-05 14:06

    I solve this problem through this approach

        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;
        }
    
    0 讨论(0)
  • 2020-12-05 14:06

    I would suggest to create another query without LiveData if you need to synchronously fetch data from database in your code.

    DAO:

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

    ViewModel:

    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();
        }
    }
    
    0 讨论(0)
  • 2020-12-05 14:13

    On the next line I am checking sections.getValue() which is always giving me null although I have data in the DataBase and later I am getting the value in the onChanged() method.

    This is a normal behavior, because queries that return LiveData, are working asynchronous. The value is null that moment.

    So calling this method

    LiveData<List<Section>> getAllSections();
    

    you will get the result later here

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

    from documentation:

    Room does not allow accessing the database on the main thread unless you called allowMainThreadQueries() on the builder because it might potentially lock the UI for a long periods of time. Asynchronous queries (queries that return LiveData or RxJava Flowable) are exempt from this rule since they asynchronously run the query on a background thread when needed.

    0 讨论(0)
提交回复
热议问题