You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Room单查询同步实现及数据赋值异常求助

问题描述

我在Android中使用Room框架,多数查询采用异步方式,但有一个查询需要设为同步执行。我不使用Kotlin的suspend语法,也不想直接操作SQLite。目前DAO中已定义同步查询方法,在Firestore查询的回调中调用Room的findByTitle方法获取Favourite对象,将其属性设置到Calculators实例后,该属性未被正确添加到calculators集合中,日志显示fave.getFav()取值正常,需解决该问题及同步查询相关疑问。

相关代码

Activity中的同步查询代码

Favourite fave = appDb.favouriteDao().findByTitle(formTitleText);

DAO代码

@Dao
public interface FavouriteDao {
    @Query("SELECT * FROM favourite")
    List<Favourite> getAll();

    @Insert
    void insertFavourite(Favourite favourite);

    @Update
    void updateFavourite(Favourite favourite);

    @Delete
    void delete(Favourite favourite);

    @Query("SELECT * FROM favourite WHERE calc_title LIKE :title LIMIT 1")
    Favourite findByTitle(String title);

    @Query("SELECT EXISTS(SELECT * FROM favourite WHERE calc_title LIKE :title LIMIT 1)")
    boolean isRowIsExist(String title);

    @Query("UPDATE favourite SET fav_status = :value WHERE calc_title LIKE :title")
    void updateFavourite(String value, String title);
}

核心业务代码

private void getCalculators(Source path) {
        db.collection("Calculators")
                .get(path)
                .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {

                    public void onComplete(@NonNull Task<QuerySnapshot> task) {
                        if (task.isSuccessful()) {

                            for (QueryDocumentSnapshot document : task.getResult()) {
                                String formTitleText = (document.getString("title"));
                                String formTagLine = (document.getString("tagLine"));
                                String numberOfFields = (document.getString("NumberFields"));
                                String formInfo = (document.getString("formInfo"));
                                String formRef = (document.getString("formRef"));
                                String formula = (document.getString("formula"));
                                String resultUnits = (document.getString("resultUnits"));
                                String formSections = (document.getString("sections"));

                                Calculators dataSection = new Calculators();
                                dataSection.setFormTitleText(formTitleText);
                                dataSection.setFormTagLine(formTagLine);
                                dataSection.setNumberOfFields(numberOfFields);
                                dataSection.setFormInfo(formInfo);
                                dataSection.setFormRef(formRef);
                                dataSection.setFormula(formula);
                                dataSection.setResultUnits(resultUnits);
                                dataSection.setFormSections(formSections);

                                // add favourite status to room db
                                Favourite fave = appDb.favouriteDao().findByTitle(formTitleText);
                                 dataSection.setFormFavourite(fave.getFav());
                                
                                calculators.add(dataSection);

解决方法

1. 修复Room同步查询的线程违规问题

Room默认禁止在主线程执行同步查询,而Firestore的onComplete回调运行在主线程,直接调用同步查询会触发线程违规,即使暂时未崩溃,也会导致数据不一致或后续集合操作异常。

合规实现方式(推荐)

将Room同步查询逻辑放到子线程执行,完成后回到主线程更新集合:

// 在Firestore回调的循环内修改
String finalTitle = formTitleText;
Executors.newSingleThreadExecutor().execute(() -> {
    // 子线程执行Room同步查询
    Favourite fave = appDb.favouriteDao().findByTitle(finalTitle);
    // 回到主线程更新数据与集合
    runOnUiThread(() -> {
        if (fave != null) { // 避免空指针异常
            dataSection.setFormFavourite(fave.getFav());
        }
        calculators.add(dataSection);
        // 若为RecyclerView数据源,需通知适配器更新
        // adapter.notifyItemInserted(calculators.size() - 1);
    });
});

临时兼容方式(不推荐)

若必须在主线程执行同步查询,需在创建RoomDatabase时开启主线程查询许可,但会增加主线程阻塞导致ANR的风险:

AppDatabase appDb = Room.databaseBuilder(context, AppDatabase.class, "db-name")
        .allowMainThreadQueries()
        .build();

2. 排查calculators集合数据未正确更新的问题

  • 线程安全校验:若calculators被多线程访问,替换为线程安全集合(如CopyOnWriteArrayList),避免并发修改导致的数据丢失。
  • 实体类setter校验:检查Calculators的setFormFavourite方法是否正确赋值,例如:
    public class Calculators {
        private String formFavourite; // 匹配fav_status的数据类型
        public void setFormFavourite(String fav) {
            this.formFavourite = fav; // 确保赋值逻辑无错误
        }
    }
    
  • 集合更新通知:若calculators是UI组件的数据源,添加元素后必须调用适配器的更新方法(如notifyDataSetChanged()),否则UI无法感知数据变化。

内容的提问来源于stack exchange,提问作者Nicholas Farmer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 04:56:15