Home > OS >  Store Image in Room Database using typeconverter to convert bitmap into bytearray. What to write in
Store Image in Room Database using typeconverter to convert bitmap into bytearray. What to write in

Time:02-10

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
}

CodePudding user response:

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 :-

enter image description here

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.

CodePudding user response:

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.

  • Related