Store Image in Room Database using typeconverter to convert bitmap into bytearray. What to write in last parameter of the model class

118
April 20, 2022, at 6:40 PM

I don't know how to pass the bitmap as byteArray in the code below. I have added the parameter in the note model class and it is of type byte array. Now how do I use the typeConverter to convert the bitmap to bytearray and pass it? Please help.

The lines in which the parameter is to be added are in "EditActivity", under savebutton.onClicklistener, where I fill the parameters for the modelClass.

Here's my TypeConverter :

class ImageConverter {
    @TypeConverter
    fun getStringFromBitmap(bitmap: Bitmap): ByteArray {
        val outputStream = ByteArrayOutputStream()
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
        return outputStream.toByteArray()
    }
    @TypeConverter
    fun getBitmapFromString(byteArray: ByteArray): Bitmap{
        return BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size)
    }
} 

And here's my "EditActivity" that adds image from gallery to the activity:

class AddEditNoteActivity : AppCompatActivity() {
    lateinit var backButton: FloatingActionButton
    lateinit var editTitle: EditText
    lateinit var editDesc: EditText
    lateinit var saveButton: FloatingActionButton
    lateinit var viewModel: JourViewModel
    lateinit var addImageButton: FloatingActionButton
    lateinit var theimage: ImageView
    lateinit var ImageURI: Uri
    lateinit var bitmap: Bitmap
    var noteID= -1
    companion object{
        const val IMAGE_REQ_CODE=100
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_add_edit_note)
        editTitle = findViewById(R.id.editNoteTitle)
        editDesc = findViewById(R.id.editNoteDescription)
        saveButton=findViewById(R.id.jourSaveButton)
        backButton=findViewById(R.id.backButton)
        addImageButton=findViewById(R.id.jourAddImgButton)
        theimage=findViewById(R.id.imageView1)

        viewModel= ViewModelProvider(
            this,
            ViewModelProvider.AndroidViewModelFactory.getInstance(application)
        ).get(JourViewModel::class.java)

        val noteType = intent.getStringExtra("noteType")
        if(noteType.equals("Edit")){
            val noteTitle = intent.getStringExtra("noteTitle")
            val noteDesc = intent.getStringExtra("noteDescription")
            noteID= intent.getIntExtra("noteID",-1)
            editTitle.setText(noteTitle)
            editDesc.setText(noteDesc)
        }

        saveButton.setOnClickListener{
            val noteTitle= editTitle.text.toString()
            val noteDesc= editDesc.text.toString()
            val storebyte=
            if(noteType.equals("Edit")){
                if(noteTitle.isNotEmpty() && noteDesc.isNotEmpty()){
                    val sdf= SimpleDateFormat("MMM, dd,yyyy")
                    val currentDate:String= sdf.format(Date())
                    val updateNote = Note(noteTitle, noteDesc, currentDate, )
                    updateNote.id=noteID
                    viewModel.updateNote(updateNote)
                    Toast.makeText(this,"Updated!",Toast.LENGTH_SHORT).show()
                    startActivity(Intent(applicationContext,MainActivity::class.java))
                    this.finish()
                }else{
                    Toast.makeText(this,"Please fill both the columns!",Toast.LENGTH_SHORT).show()
                }
            }else{
                if(noteTitle.isNotEmpty() && noteDesc.isNotEmpty()){
                    val sdf= SimpleDateFormat("MMM dd,yyyy")
                    val currentDate:String= sdf.format(Date())
                    viewModel.addNote(Note(noteTitle,noteDesc,currentDate,))
                    Toast.makeText(this,"Added!",Toast.LENGTH_SHORT).show()
                    startActivity(Intent(applicationContext,MainActivity::class.java))
                    this.finish()
                }else{
                    Toast.makeText(this,"Please fill both the columns!",Toast.LENGTH_SHORT).show()
                }
            }

        }
        backButton.setOnClickListener{
            val intent = Intent(this@AddEditNoteActivity,MainActivity::class.java)
            startActivity(intent)
            this.finish()
        }

        addImageButton.setOnClickListener{
            pickImageGallery()
        }
    }
    private fun pickImageGallery() {
        val intent = Intent(Intent.ACTION_PICK)
        intent.type = "image/"
        startActivityForResult(intent, IMAGE_REQ_CODE)
    }
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?){
        super.onActivityResult(requestCode, resultCode, data)
        if(requestCode== IMAGE_REQ_CODE && resultCode==RESULT_OK){
             ImageURI  = data?.data!!

            if (ImageURI!=null){
                theimage.setImageURI(data?.data)
                try {
                    bitmap =MediaStore.Images.Media.getBitmap(contentResolver, ImageURI)
                    theimage.setImageBitmap(bitmap)
                }catch(exception: IOException){
                    exception.printStackTrace()
                }
            }
        }
    }
}

ModelClass:

@Entity(tableName = "jourTable")
class Note(
    @ColumnInfo(name = "title") val jourTitle:String,
    @ColumnInfo(name = "description") val jourDescription:String,
    @ColumnInfo(name = "date") val jourDate:String,
    @ColumnInfo(name = "image", typeAffinity = ColumnInfo.BLOB) val jourImage: ByteArray
) {
    @PrimaryKey(autoGenerate = true)var id=0
}
Answer 1

Now how do I use the typeConverter to convert the bitmap to bytearray and pass it?

Typically you don't use the Type Converter, you let Room know about it and Room then uses it.

So taking getStringFromBitmap(bitmap: Bitmap): ByteArray (should really be getByteArrayFromBitmap)

Then in the class annotaed with @Database ADD an @TypeConverters annotation (NOTE the plural not singular) that defines the class where the Type Converters are located e.g :-

@TypeConverters(ImageConverter::class) //<<<<< ADDED
@Database(entities = [Note::class], version = 1, exportSchema = false)
abstract class TheDatabase: RoomDatabase() {
    ....

Now this will convert a BitMap to a ByteArray as such you don't code the type as ByteArray but instead as Bitmap.

You can use the type converter and bypass Room's automatic use of it.

Let's say you have (uses both) :-

@Entity(tableName = "jourTable")
class Note(
    @ColumnInfo(name = "title") val jourTitle:String,
    @ColumnInfo(name = "description") val jourDescription:String,
    @ColumnInfo(name = "date") val jourDate:String,
    @ColumnInfo(name = "image", typeAffinity = ColumnInfo.BLOB) val jourImage: Bitmap, //<<<<< will use the TypeConverter
    @ColumnInfo(name = "altImage") val jourAltImage: ByteArray //<<<<< will not use the TypeConverter
) {
    @PrimaryKey(autoGenerate = true)var id=0
}

And then have an @Dao annotated interface or abstract class such as :-

@Dao
abstract class AllDao {
    @Insert
    abstract fun insert(note: Note): Long
}

Then in an activity you could use:-

    dao.insert(
        Note
            ("Title1","Description1","2021-02-08",
            bm, /*<<<<< ROOM will know to get the ByteArray from the Bitmap and utilise the TypeConverter */
            ImageConverter().getStringFromBitmap(bm) /* use the TypeConverter to get a ByteArray (not needed)*/
        )
    )

As a working example consider the following :-

    val bm = BitmapFactory.decodeByteArray(ByteArray(0),0,0) // results in null Bitmap
    val db = TheDatabase.getInstance(this);
    val dao = db.getAllDao()
    dao.insert(
        Note
            ("Title1","Description1","2021-02-08",
            bm, /*<<<<< ROOM will know to get the ByteArray from the Bitmap and utilise the TypeConverter */
            ImageConverter().getStringFromBitmap(bm) /* use the TypeConverter to get a ByteArray (not needed)*/
        )
    )

and a modified TypeConverter which handles the null Bitmap by returning a ByteArray of 10 0 bytes i.e. :-

@TypeConverter
fun getStringFromBitmap(bitmap: Bitmap?): ByteArray {
    if (bitmap == null) {
        return ByteArray(10)
    }
    val outputStream = ByteArrayOutputStream()
    bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
    return outputStream.toByteArray()
}

Then, when run, the result as per App Inspection is :-

i.e The image column is the 10 0 bytes as produced by the TypeConverter automatically invoked by Room. The altimage column likewise is 10 0 bytes but via the TyoeConverter manually invoked.

When extracting data again Room will automatically invoke the 2nd TypeConverter for the image column/field the altImage column/field would be returned as a ByteArray.

Answer 2

UPDATE:

With the help of @MikeT 's response I was able to store data in the database. And with the help of this I was able to pass bitmap from one activity to another to load the image.

The function is working now, if anyone wants to check out the issue/repo, here you go.

Rent Charter Buses Company
READ ALSO
google reset new key certificate for me but certificate not working

google reset new key certificate for me but certificate not working

i am reset my certificate APK google play console

81
How to update and delete firebase data in android java?

How to update and delete firebase data in android java?

I am getting nothing in response while updating or deleting the data this line but the inserting and retriving works fine and please do answer i am new to android development

112
Flutter: the action button in flutter callkit incoming package didn&#39;t work

Flutter: the action button in flutter callkit incoming package didn't work

the action button in flutter callkit incoming package didn't workI tried a lot but in the background it doesnot work

84
Android WebView onPermissionRequest is not calling

Android WebView onPermissionRequest is not calling

I m new to Pyjnius and androidI m trying to make a video calling app But my onPermissionRequest is not Called when my WebView PopUps

89