【问题标题】:Room database Livedata getValue() returns null房间数据库 Livedata getValue() 返回 null
【发布时间】:2018-04-23 09:50:46
【问题描述】:

我试图使用 LiveData 和 viewmodel 从房间中获取自定义对象数据列表。使用 Livedata 的 getValue() 方法时,返回 null 但获取列表直接显示实际数据。如何在 viewmodel 类中使用 LiveData 获取 Period 类的列表。

实体类

@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;
}
}

转换器类

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 类

@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(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();



}

在视图模型类中获取数据方法

 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();

}

【问题讨论】:

  • 不要使用AsyncTask和LiveData.getValue() ...使用LiveData.observe()
  • new AsyncTask&lt;Void, Void, LiveData&lt;List&lt;Period&gt;&gt;&gt;() { 你是从哪里得到这个想法的?我很确定这不是codelabs.developers.google.com/codelabs/… 中描述的方式
  • 根据文档,我认为应该异步调用 fetch 操作,这就是我犯错误的原因。顺便说一句,谢谢大家澄清我的想法。
  • 我们应该继续使用AsyncTask吗?

标签: android viewmodel dao android-room android-livedata


【解决方案1】:

通常Room 处理查询同步,但与LiveData 一起使用这些查询以ASynchronous 方式执行,所以当您调用此行时:

LiveData<List<Period>> periodList = MyApplication.getDatabase().dao().getAllPeriodList();

,你实际上得到了一个 empty 容器,它将在查询执行并完成后得到更新。因此,要获得查询结果,甚至首先要执行查询,您必须观察返回的LiveData。

现在通常的情况是将Room从ViewModel提供的LiveData传递到您的View,然后观察LiveData视图的变化。

ViewModel内部:

public LiveData<List<Period>> getAllPeriods() {
    return MyApplication.getDatabase().dao().getAllPeriodList();
}

内部视图:

viewModel.getAllPeriods().observe(this, new Observer<List<Period>>() {
    @Override
    public void onChanged(@Nullable List<Period> periods) {
        updateList(periods); 
    }
});

【讨论】:

  • 谢谢你的解释,现在我完全清楚了。
  • @Razon 欢迎您,我也提供了代码示例,希望对您有所帮助
【解决方案2】:

事实是,

  1. Asynctask 正在后台异步的另一个线程上运行
  2. Livedata 就像漂浮在数据库上以查看更改。

因此完成Asyntask 的提取操作需要时间。您可以通过在 10 秒延迟的处理程序内测试 Asynctask 来查看它。 所以最好直接在视图模型中调用 fetch 操作并将其作为 livedata.observe 发送到活动/片段。

【讨论】:

  • 太好了,我用处理程序测试过,它是真实的。再次感谢您的解释。与 asynctask 一起更好地了解房间操作。
  • @Razon 但请不要使用处理程序,就像 Hossain 所说的将 livedata 传递给您的视图类并观察它
  • @keivan,我告诉过使用处理程序仅用于测试以查看实际发生的情况。
猜你喜欢
  • 2020-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-08
  • 2021-12-08
相关资源
最近更新 更多