Search code examples
androidviewmodeldaoandroid-roomandroid-livedata

Room database Livedata getValue() returns null


I was trying to fetch a list of custom object data from room using LiveData and viewmodel. While using Livedata's getValue() method, returns null but getting list directly shows the actual data. How can I get List of Period class using LiveData in viewmodel class.

Entity classes

@Entity
public class Period {

@PrimaryKey
@NonNull
String header;
@TypeConverters(WritterConverter.class)
ArrayList<Writter> writters;

public Period(String header, ArrayList<Writter> writters) {
    this.header = header;
    this.writters = writters;
}

public String getHeader() {
    return header;
}

public ArrayList<Writter> getWritters() {
    return writters;
}


}

@Entity
public class Writter {

String birth;
String death;
String name;
ArrayList<String> novels;

public Writter(){}

public Writter(String birth, String death, String name, ArrayList<String> novels) {
    this.birth = birth;
    this.death = death;
    this.name = name;
    this.novels = novels;
}

public String getBirth() {
    return birth;
}

public String getDeath() {
    return death;
}

public String getName() {
    return name;
}

public ArrayList<String> getNovels() {
    return novels;
}
}

Converter Class

public class WritterConverter {

@TypeConverter
public static ArrayList<Writter> fromString(String value){
    Type listType = new TypeToken<ArrayList<Writter>>(){}.getType();
    return new Gson().fromJson(value, listType);
}

@TypeConverter
public static String fromArrayList(ArrayList<Writter> list){
    Gson gson = new Gson();
    String json = gson.toJson(list);
    return json;
}

}

DAO class

@Dao
@TypeConverters({WritterConverter.class})
public interface DAO {

@Insert(onConflict = OnConflictStrategy.REPLACE)
void insertPeriod(Period period);

@Query("SELECT * FROM Period WHERE header LIKE :header")
Period getPeriodList(String header);

@Query("SELECT * FROM Period")
LiveData<List<Period>> getAllPeriodList();

}

Database

@Database(version = 1, entities = {Period.class})
public abstract class MyDatabase extends RoomDatabase{

static MyDatabase databaseInstance;

public static MyDatabase getDatabaseInstance(Context context) {
    if (databaseInstance == null)
        databaseInstance = Room
                .databaseBuilder(context, MyDatabase.class, "testDatabase1")
                .fallbackToDestructiveMigration()
                //     .addMigrations(FROM_1_TO_2)
                .build();

    return databaseInstance;
}

abstract public DAO dao();



}

Get Data method in viewmodel class

 private void getDataFromDatabase() {

    new AsyncTask<Void, Void, LiveData<List<Period>>>() {
        @Override
        protected LiveData<List<Period>> doInBackground(Void... voids) {
            LiveData<List<Period>> periodList = MyApplication.getDatabase().dao().getAllPeriodList();
          //  Period periodList = MyApplication.getDatabase().dao().getWriterList(EndPoints.THE_OLD_ENGLISH_PERIOD);
            return periodList;
        }

        @Override
        protected void onPostExecute(LiveData<List<Period>> aVoid) {
            super.onPostExecute(aVoid);
         //  Period period = aVoid.getValue().get(0);
            Log.d("header", aVoid.getValue().get(0).getHeader());
        }
    }.execute();

}

Solution

  • The fact is,

    1. Asynctask is running on another thread in background asynchronously
    2. Livedata is working like floating over database to see the changes.

    So it takes time to accomplish the fetch operation for Asyntask. You can see it by testing the Asynctask within a handler of 10 sec delay. So its better to directly call the fetch operation in view model and send it to activity/fragment as livedata.observe.