Номер.Первый запрос возвращает нулевое значение - PullRequest
0 голосов
/ 13 декабря 2018

В моем проекте 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)
    }
}
}

CountryCode entity

@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 (это означает, что результатов нет).Но при следующих запросах и при следующих запусках он работает великолепно - он возвращает 7 и 34 соответственно параметру порядка. Так что я очень запутался с этой ошибкой.Пожалуйста, помогите мне решить эту проблему

Ответы [ 2 ]

0 голосов
/ 17 декабря 2018

Это на самом деле не удивительно, база данных предварительно заполнена асинхронно, и вы не уведомлены о том, когда данные фактически вставлены.

Вы можете проверить официальные образцы 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);
}
0 голосов
/ 14 декабря 2018

Это потому, что он, вероятно, запрашивает базу данных, когда она пуста.так что лучший способ решить эту проблему - вернуть LiveData вместо примитива int.тогда LiveData позаботится об обновлении пользовательского интерфейса при заполнении базы данных.

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