在我的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。因此,我对该错误感到非常困惑。请帮助我解决这个问题
答案 0 :(得分:0)
那是因为它可能在数据库为空时查询数据库。因此解决此问题的最佳方法是返回LiveData而不是原始int。那么LiveData将在填充数据库时负责更新UI。
@Query("SELECT phone_code FROM country_code WHERE order_list = :order")
fun selectCountryCodeByOrder(order: Int): LiveData<SomeType>
答案 1 :(得分:0)
这并不奇怪,数据库是异步预填充的,并且实际上没有插入数据的时间也不会通知您。
您可以检入正式的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);
}
You need a MediatorLiveData
to consume the 0
result for when the results are not yet available
mObservableProducts.addSource(mDatabase.productDao().loadAllProducts(),
productEntities -> {
if (mDatabase.getDatabaseCreated().getValue() != null) {
mObservableProducts.postValue(productEntities);
}
});
您可以将结果显示为LiveData<...>
,以便在结果实际存在时通知您