Android DAO Log Database

Given a DAO database like this:

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 MyTable") List<MyItem> all(); @Query("SELECT * FROM MyTable WHERE date = :date AND language = :language") MyItem byDate(Date date, String language); } 

Is there a way to have Logger or something similar added to MyDao so that I can see which statements are being executed. This would be very useful during development, because I could immediately verify that the functions were converted to the expected SQL statement or not.

+15
source share
4 answers

At the DAO level, there seems to be no clue for this. There are callbacks associated with opening and updating the database, but not arbitrary things.

You can submit a function request though. I agree that this may be helpful. Even better would be the universal OkHttp-style interceptor structure.

+10
source

According to the Room document , it checks the compilation time, so if your SQL statement is invalid, the compilation itself failed and the correct error message is displayed in the log.

Also, the generated code is debugged by default and can be found in the path below.

assembly> created> source> apt> your package> yourDao_Impl.java

This class contains the implementation of your DAO, you can debug this class as you debug other classes in your project. :-)

Example:

enter image description here

+8
source

When I have some unknown error when inserting or updating a row in the db room, Android does not detect errors in the debug console. One thing I found is how to check what happens during debugging:

 try { someSource.update(someRow) } catch (e: Throwable) { println(e.message) } 

Output:

UNIQUE error: quiz.theme (code 2067)

+4
source

I was able to achieve this using the Select query hack. This will not work for insert / update / delete operations :)

Create a separate RoomLoggingHelper class as follows

 import android.annotation.SuppressLint import 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" object RoomLoggingHelper { @SuppressLint("RestrictedApi") fun getStringSql(query: RoomSQLiteQuery): String { val argList = arrayListOf<String>() val bindingTypes = query.getBindingTypes() var i = 0 while (i < bindingTypes.size) { val bindingType = bindingTypes[i] when (bindingType) { NULL -> 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++ } return String.format(query.sql.replace("?", "%s"), *argList.toArray()) } fun getStringSql(query: String?, args: Array<out Any>?): String? { return if (query != null && args != null) { String.format(query.replace("?", "%s"), *args) } else "" } } private fun RoomSQLiteQuery.getBindingTypes(): IntArray { return javaClass.getDeclaredField("mBindingTypes").let { field -> field.isAccessible = true return@let field.get(this) as IntArray } } private fun RoomSQLiteQuery.getLongBindings(): LongArray { return javaClass.getDeclaredField("mLongBindings").let { field -> field.isAccessible = true return@let field.get(this) as LongArray } } private fun RoomSQLiteQuery.getStringBindings(): Array<String> { return javaClass.getDeclaredField("mStringBindings").let { field -> field.isAccessible = true return@let field.get(this) as Array<String> } } private fun RoomSQLiteQuery.getDoubleBindings(): DoubleArray { return javaClass.getDeclaredField("mDoubleBindings").let { field -> field.isAccessible = true return@let field.get(this) as DoubleArray } } private fun RoomSQLiteQuery.getIntBindings(): IntArray { return javaClass.getDeclaredField("mBindingTypes").let { field -> field.isAccessible = true return@let field.get(this) as IntArray } } 

Or you can download this file here.

Add this file to your project and call it from the Room Database class as follows: override both query methods as follows

 override fun query(query: SupportSQLiteQuery?): Cursor { //This will give you the SQL String val queryString = RoomLoggingHelper.getStringSql(query as RoomSQLiteQuery) //You can log it in a way you like, I am using Timber Timber.d("$ROOM_LOGGING_TAG $queryString") return super.query(query) } override fun query(query: String?, args: Array<out Any>?): Cursor { //This will give you the SQL String val queryString = RoomLoggingHelper.getStringSql(query, args) //You can log it in a way you like, I am using Timber Timber.d("$ROOM_LOGGING_TAG $queryString") return super.query(query, args) } 

Denial of responsibility:

  • I use Reflection to get string SQL, therefore, use this ONLY in debug mode
  • This is written in haste and may contain errors, it would be advisable to save it in a try-catch
  • Also, I checked it for string arguments, should work long and double, will not work for Blobs
+1
source

Source: https://habr.com/ru/post/1271719/


All Articles