【问题标题】:Room. The first query returns null value房间。第一个查询返回空值
【发布时间】:2019-05-14 14:12:47
【问题描述】:

在我的 Android 项目中,我使用 Room 库来处理 SQLite 数据库。我使用我的数据库来保存国家电话代码。我的数据库预装了两个国家(观看 populateDatabaseWithCountryCodes(dao: PhoneCodeDao) 函数);

@Database(entities = [CountryCode::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun createPhoneCodeDao(): PhoneCodeDao

companion object {
    @Volatile
    private var INSTANCE: AppDatabase? = null

    fun getDatabase(context: Context): AppDatabase {
        val tempInstance = INSTANCE
        if (tempInstance != null) {
            return tempInstance
        }
        synchronized(this) {
            val instance = Room.databaseBuilder(
                context.applicationContext,
                AppDatabase::class.java,
                "database"
            ).addCallback(PrepopulationCallback)
                .build()
            INSTANCE = instance
            return instance
        }
    }
}

object PrepopulationCallback : RoomDatabase.Callback() {
    override fun onCreate(db: SupportSQLiteDatabase) {
        super.onCreate(db)
        INSTANCE?.let { database ->
            GlobalScope.launch(Dispatchers.IO) {
                populateDatabaseWithCountryCodes(database.createPhoneCodeDao())
            }
        }
    }

    private fun populateDatabaseWithCountryCodes(dao: PhoneCodeDao) {
        val spainPhoneCode = CountryCode(0, "Spain", 34)
        val rusPhoneCode = CountryCode(1, "Russia", 7)
        val list = LinkedList<CountryCode>()
        list.add(spainPhoneCode)
        list.add(rusPhoneCode)
        dao.insertAllCountryCodes(list)
    }
}
}

国家代码实体

@Entity(tableName = "country_code")
data class CountryCode(
@SerializedName("order")
@ColumnInfo(name = "order_list") val order: Int,
@SerializedName("name")
@ColumnInfo(name = "country_name_eng") val name: String,
@SerializedName("phone_code")
@ColumnInfo(name = "phone_code") val phoneCode: Int
) {
@ColumnInfo(name = "id")
@PrimaryKey(autoGenerate = true)
var id: Long = 0
}

DAO 接口

@Dao
interface PhoneCodeDao {

@Insert
fun insertAllCountryCodes(list: List<CountryCode>)

@Query("SELECT phone_code FROM country_code WHERE order_list = :order")
fun selectCountryCodeByOrder(order: Int): Int

}

在我的应用程序中,我按顺序选择国家代码(观看功能 selectCountryCodeByOrder(order: Int): Int)。我在 async{} 协程中异步调用此函数。但是我有一个非常奇怪的错误:安装后我在设备上首次启动我的应用程序并进行查询 - 查询结果为 0(这意味着没有结果)。但是在下一次查询和下一次启动期间,它工作得非常好——它根据 order 参数返回 7 和 34。 所以我对那个错误感到非常困惑。请帮我解决这个问题

【问题讨论】:

  • 我的事情是因为您正在异步填充数据尝试在Executors.newSingleThreadScheduledExecutor().execute { //here } 内部执行回调

标签: android android-sqlite android-room android-architecture-components


【解决方案1】:

那是因为它可能在数据库为空时查询。所以解决这个问题的最好方法是返回 LiveData 而不是原始 int。然后 LiveData 将负责在填充数据库时更新 UI。

 @Query("SELECT phone_code FROM country_code WHERE order_list = :order")
fun selectCountryCodeByOrder(order: Int): LiveData<SomeType>

【讨论】:

    【解决方案2】:

    这并不奇怪,数据库是异步预填充的,您不会收到实际插入数据的通知。

    您可以查看官方 AAC 示例,特别是要通知的 BasicSample

    .

    private final MutableLiveData<Boolean> mIsDatabaseCreated = new MutableLiveData<>();
    
    public static AppDatabase getInstance(final Context context, final AppExecutors executors) {
        if (sInstance == null) {
            synchronized (AppDatabase.class) {
                if (sInstance == null) {
                    sInstance = buildDatabase(context.getApplicationContext(), executors);
                    sInstance.updateDatabaseCreated(context.getApplicationContext());
                }
            }
        }
        return sInstance;
    }
    
    /**
     * Build the database. {@link Builder#build()} only sets up the database configuration and
     * creates a new instance of the database.
     * The SQLite database is only created when it's accessed for the first time.
     */
    private static AppDatabase buildDatabase(final Context appContext,
            final AppExecutors executors) {
        return Room.databaseBuilder(appContext, AppDatabase.class, DATABASE_NAME)
                .addCallback(new Callback() {
                    @Override
                    public void onCreate(@NonNull SupportSQLiteDatabase db) {
                        super.onCreate(db);
                        executors.diskIO().execute(() -> {
                            // ...create the database here
    
                            // notify that the database was created and it's ready to be used
                            database.setDatabaseCreated();
                        });
                    }
                })
            .build();
    }
    
    /**
     * Check whether the database already exists and expose it via {@link #getDatabaseCreated()}
     */
    private void updateDatabaseCreated(final Context context) {
        if (context.getDatabasePath(DATABASE_NAME).exists()) {
            setDatabaseCreated();
        }
    }
    
    private void setDatabaseCreated(){
        mIsDatabaseCreated.postValue(true);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-12-12
      • 2021-09-01
      • 2012-10-10
      • 2020-02-12
      • 2023-01-21
      • 2017-09-02
      • 1970-01-01
      相关资源
      最近更新 更多