How Android Room stores ByteArray as Blob?

Viewed 24

I'm storing ByteArray in room in this way :

Entity {

@ColumnInfo(name = "pin", typeAffinity = ColumnInfo.BLOB)
    val pin: ByteArray?
}

Dao {
    
        @Query("UPDATE tbl SET pin=:pin WHERE id=:id")
        fun updatePin(id: String, pin: ByteArray)
    }

When I'm checking table data with Android Studio I see some data like this

5994471ABB01112AFCC18159F6CC74B4

So, my question is how room converts ByteArray to this data? And how we can re-convert this data to ByteArray in other languages or platforms?

1 Answers

how room converts ByteArray to this data?

Room and also the underlying android SQLite API converts each byte in the byte array into a stream of bytes

  • the first element being 59 (hex) 89
  • the second element being 94 (hex) 148 decimal
  • and so on

And how we can re-convert this data to ByteArray in other languages or platforms?

You reconvert in Room by extracting the pin object and the pin field will be the original ByteArray. How you came about creating the ByteArray is reversed to use that ByteArray.

Other languages/platforms could do the same via the SQLite interface and you would process the bytestream aka ByteArray using suitable code.

Any file Images, Word documents, spreadhseets .... is a stream of bytes.

For any file to be of use then it needs to be opened with a suitable/appropriate tool.

  • Open an SQLite database using say notepad then you could get something like:-

  • enter image description here

  • Open the same file (byte stream which is a ByteArray) using an SQlite tool then you could get:-

enter image description here

  • Open the same file in a Hex editor then :-

  • enter image description here

    • As you can see the ByteArray would be stored as 53514C697465 ....

So as much as a name or a numeric value stored in the database only has a meaning if interpreted correctly, so does a byte stream aka ByteArray or a BLOB using SQLite terminology.

You could copy the database (using device explorer) and the file(s) could be used by SQLite tools on other platforms e.g. Navicat for SQlite, DB Browser SQLite Studio, DBeaver and so on.

  • How these tools display a BLOB is dependant upon the tool.

You can also do the reverse, that is create a database elsewhere on whatever platform, using whatever language and copy the resultant file(s) to the device in Android studio and, with the appropriate programming/code open and use the database via the SQLite API/interface.

  • This process is frequently used when providing a pre-packaged database.

Replicating the conversion

Using the data My Byte Array such as val myByteArray = "My Byte Array".toByteArray()

And a Class/Table such as:-

@Entity
data class Blobby(
    @PrimaryKey
    var id: Long?=null,
    var theBlob: ByteArray= ByteArray(0)
)

And some functions in an @Dao annotated class e.g. :-

@Dao
interface Roomdao {
    @Insert
    fun insert(blobby: Blobby): Long
    @Query("INSERT INTO blobby (theBlob) VALUES(:theBlob);")
    fun insert(theBlob: ByteArray): Long
}

And the following in an activity ( with .allowMainThreadQueries for brevity/convenience) :-

    db = TheDatabase.getInstance(this)
    dao = db.getRoomdao()

    val myByteArray = "My Byte Array".toByteArray()
    dao.insert(Blobby(null,myByteArray))
    dao.insert(myByteArray)

    val sb = StringBuilder()
    for (b in myByteArray) {
        sb.append(Integer.toHexString(b.toInt()))
    }
    db.openHelper.writableDatabase.execSQL("INSERT INTO blobby (theBlob) VALUES(x'$sb');")

The blobby table in database would be:-

enter image description here

So that is 3 ways to achieve the same outcome (bar the id).

The 3rd replicates what Room (via the SQLite API) does.

i.e. for each byte in the array the hexadecimal value of the byte is extracted and added to the previous value resulting in the stored value. However, this is then enclosed in single quotes and preceded with a x (or X) thus an SQLite BLOB literal value as per

BLOB literals are string literals containing hexadecimal data and preceded by a single "x" or "X" character. Example: X'53514C697465'

  • https://www.sqlite.org/lang_expr.html#literal_values_constants_

  • Note you can't use traditional/convenience functions as Room encloses values in single quotes and would therefore ensclose x'....' in single quotes and store it as a string (TEXT). Hence the get around of using the execSQL method to circumvent the value being enclosed.

Related