Android Room Database DAO debug log –

January 7, 2021 by No Comments

Frage oder Problem in der Entwicklung:

Gegeben eine DAO-Raumdatenbank wie diese:

import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Query;

Import java.util.Date;
Import java.util.List;

@Dao
public interface MyDao {.

@Query(SELECT * FROM MeineTabelle)
Liste all();

@ COLOR(SELECT * FROM MyTable WHERE date = :date AND language = :language)
MyItem byDate(Date date, String language);

}

Gibt es eine Möglichkeit, ein Protokoll oder etwas Ähnliches zu MyDao hinzuzufügen, damit ich sehen kann, welche Anweisungen ausgeführt werden. Dies wäre während der Entwicklung sehr nützlich, da ich sofort überprüfen könnte, ob die Funktionen korrekt in die erwartete SQL-Anweisung umgesetzt wurden oder nicht.

Wie kann ich dieses Problem lösen?

Lösung Nr. 1:

Unter der Annahme, dass Room das Sqlite-Framework als Datenbank verwendet, können Anweisungen recht einfach protokolliert werden. Einzige Einschränkung: Es kann nur auf einem Emulator durchgeführt werden.

Aus SQLiteDebug.java:

/**
* Steuert das Drucken von SQL-Abfragen bei deren Ausführung.
*
* Aktivieren Sie die Verwendung von adb shell setprop log.tag.SQLiteStatements VERBOSE.
*/
public static final boolean DEBUG_SQL_STATEMENTS =
Log.isLoggable(SQLiteStatements, Log.VERBOSE);

Der Standardwert von log.tag.SQLiteStatements ist nicht gesetzt:

[email protected]:~$ adb shell getprop log.tag.SQLiteStatements

Nach der oben genannten Dokumentation, um die Eigenschaft zu etablieren, die wir verwenden sollen:

[email protected]:~$ adb shell setprop log.tag.SQLiteStatements VERBOSE
[email protected]:~$ adb shell getprop log.tag.SQLiteStatements
VERBOSE

Wie Sie sehen können, wurde der VERBOSE-Wert erfolgreich eingestellt. Wenn wir jedoch unsere Anwendung erneut ausführen, werden diese Anweisungen nicht gedruckt. Damit das funktioniert, müssen wir alle Dienste neu starten, indem wir die adb-Shell stoppen und dann die adb-Shell starten.
Wenn Sie dies mit einem regulären Gerät versuchen, erhalten Sie folgenden Fehler (ausprobiert mit Pixel XL / stock Android 9):

[email protected]:~$ adb shell start
start: must be root
[email protected]:~$ adb root
adbd kann in Produktionsbuilds nicht als root laufen.

Вот почему мы должны использовать эмулятор:

[защита по электронной почте]:~$ adb корневой
перезапуск adbd как корневой
[защита по электронной почте]:~$ остановка оболочки
[защита по электронной почте]:~$ запуск оболочки adb

Эмулятор перезапустится.
Запустите ваше приложение и вы увидите аналогичные Sqlite утверждения в logcat:

V/SQLiteStatements: /my_db: BEGIN EXCLUSIVE;
V/SQLiteStatements: /my_db: CREATE TABLE ЕСЛИ НЕ ВЫПАДАЕТ room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)
V/SQLiteStatements: /my_db: INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 3cb5664b6da264c13388292d98141843)
V/SQLiteStatements: /my_db: CREATE TABLE ЕСЛИ НЕ ВЫПАДАЕТ `MyTable` (`id` TEXT NOT NULL, `date` INTEGER, `language` TEXT, PRIMARY KEY(`id`))

V/SQLiteStatements: /my_db: BEGIN EXCLUSIVE;
V/SQLiteStatements: /my_db: PRAGMA temp_store = MEMORY;
V/SQLiteStatements: /my_db: PRAGMA recursive_triggers=ON;
V/SQLiteStatements: /my_db: CREATE TEMP ТАБЛИЦА room_table_modification_log(версия INTEGER PRIMARY KEY AUTOINCREMENT, table_id INTEGER)
V/SQLiteStatements: /my_db: КОММИТ;

V/SQLiteStatements: /my_db: ВЫБЕРИТЕ * Из MyTable
V/SQLiteStatements: /my_db: ВЫБЕРИТЕ * ОТ МИСТЕБЛЯ Где дата = 1551562171387 И язык=en

Чтобы отменить изменения, используйте эти команды:

[защита по электронной почте]:~$ adb shell setprop log.tag.SQLiteStatements “”
[защита по электронной почте]:~$ adb shell getprop log.tag.SQLiteStatements
[защита по электронной почте]:~$ adb shell stop
[защита по электронной почте]:~$ adb shell start
[защита по электронной почте]:~$ adb unroot
restarting adbd as non root

Решение № 2:

В соответствии с документом Room, он выполняет проверку времени компиляции, поэтому, если ваш SQL оператор не корректен, компиляция сама по себе не удалась, и в журнале отображается соответствующее сообщение об ошибке.

Также сгенерированный код отлаживается по умолчанию и может быть найден по указанному ниже пути.

build > generated > source > apt > your Package > yourDao_Impl.java

Этот класс содержит реализацию вашей DAO, которую вы можете отлаживать по мере отладки других классов в вашем проекте.

Пример :

Решение № 3:

На уровне DAO крючков для этого, похоже, нет. Существуют обратные вызовы, связанные с открытием и обновлением базы данных, но не произвольные.

Но вы можете отправить запрос на функцию. Я согласен, что это может быть полезно. Лучше бы это был общий каркас перехватчика в стиле OkHttp.

Решение № 4:

Когда я получил какую-то неизвестную ошибку при вставке или обновлении строки в комнате db Android не показывает никакой ошибки в отладочной консоли. Одна вещь, которую я нашел, как проверить, что происходит во время отладки:

попробуйте { someSource.update(someRow) } catch (e: Throwable) { println(e.message)) }

Выход –

Ограничение UNIQUE не удалось: quiz.theme (код 2067)

Решение № 5:

Я смог достичь этого с помощью взлома для Select запросов. Это не будет работать для операций вставки/обновления/удаления.

Создайте отдельный класс RoomLoggingHelper следующим образом

импорт android.annotation.suppressLint
импорт androidx.room.RoomSQLiteQuery

private const val NULL = 1
private const val LONG = 2
private const val DOUBLE = 3
private const val STRING = 4
private const val BLOB = 5
private const val NULL_QUERY = NULL

const val ROOM_LOGGING_TAG = roomQueryLog

объект RoomLoggingHelper.

@SuppressLint(RestrictedApi)
fun getStringSql(request: RoomSQLiteQuery): Строка {
val argList = arrayListOf()
val bindingTypes = query.getBindingTypes()
var i = 0

пока (i argList.add(NULL_QUERY)
LONG -> argList.add(query.getLongBindings()[i].toString())
DOUBLE -> argList.add(query.getDoubleBindings()[i].toString())
STRING -> argList.add(query.getStringBindings()[i].toString())
}
i++
}

возвращает String.format(query.sql.replace(?, %s), *argList.toArray())
}.

fun getStringSql(request: String?, args: Array?): Стринг? {
return if (request != null && args != null) {
String.format(request.replace(?, %s), *args)
} else

}
}

приватное развлечение RoomSQLiteQuery.getBindingTypes(): Внутренний массив

вернуть javaClass.getDeclaredField(mBindingTypes).let { поле ->
field.isAccessible = true
[email protected] field.get(this) as IntArray
}
}

приватное развлечение RoomSQLiteQuery.getLongBindings(): LongArray

вернуть javaClass.getDeclaredField(mLongBindings).let { поле ->
field.isAccessible = true
[email protected] field.get(this) as LongArray
}
}

приватное развлечение RoomSQLiteQuery.getStringBindings(): Массив

вернуть javaClass.getDeclaredField(mStringBindings).let { поле ->
field.isAccessible = true
[email protected] field.get(this) as Array
}
}

приватное развлечение RoomSQLiteQuery.getDoubleBindings(): DoubleArray

вернуть javaClass.getDeclaredField(mDoubleBindings).let { поле ->
field.isAccessible = true
[email protected] field.get(this) as DoubleArray
}
}

приватное развлечение RoomSQLiteQuery.getIntBindings(): Внутренний массив

вернуть javaClass.getDeclaredField(mBindingTypes).let { поле ->
field.isAccessible = true
[email protected] field.get(this) as IntArray
}
}

Или вы можете скачать этот файл отсюда

Добавьте этот файл в свой Проект и вызовите его из класса Базы данных комнат следующим образом:
Переопределить оба метода запроса, как это

переопределить забавный запрос (запрос: SupportSQLiteQuery?): Курсор {
//Это даст вам SQL String
val queryString = RoomLoggingHelper.getStringSql(запрос как RoomSQLiteQuery)
//Вы можете записать его в журнал так, как вам нравится, я использую Timber
Timber.d($ROOM_LOGGING_TAG $queryString)
возвращаю super.query(запрос)
}

отменить забавный запрос (запрос: Строка?, аргументы: Массив?): Курсор {
//This will give you the SQL String
val queryString = RoomLoggingHelper.getStringSql(request, args)
//Вы можете записать его в журнал так, как вам нравится, я использую Timber
Timber.d($ROOM_LOGGING_TAG $queryString)
return super.request(query, args)
}

Отказ от ответственности:

  • Я использую Reflection для получения строки SQL, поэтому использую это ТОЛЬКО в DEBUG режиме
  • Это написано в спешке и может содержать ошибки, было бы разумно держать это в блоке try-catch
  • Также, я протестировал его для строковых аргументов, должен работать долго и вдвое, не будет работать для Blobs

Удачи!

Related Tags:

android mock room database,room android example,search in room database android,android room repository,android-room query,room dao,android room fetch data,android room multiple tables,android-room log queries,android-room print query,android debug database query,debug room database android,android-room dynamic query

Leave a Comment

Your email address will not be published. Required fields are marked *