I am using room persistence library for my android application, Now I have to insert image in my db. I successfully define @Entity for the primitive data type. and also thro
As Pinakin mentioned, it is not recommended to store an image into database and file path would be better but if it is required to store image I would suggest compress the image to below 2 MB (here is an example) to avoid breaking app. Room supports BLOB for image. Entity class in kotlin:
ImageTest.kt
@Entity class ImageTest { @PrimaryKey(autoGenerate = true) var id: Int = 1 @ColumnInfo(typeAffinity = ColumnInfo.BLOB) var data: ByteArray? = null }
ImageDao.kt
@Dao interface ImageTestDao { @Insert(onConflict = OnConflictStrategy.REPLACE) fun upsertByReplacement(image: List<ImageTest>) @Query("SELECT * FROM image") fun getAll(): List<ImageTest> @Query("SELECT * FROM image WHERE id IN (:arg0)") fun findByIds(imageTestIds: List<Int>): List<ImageTest> @Delete fun delete(imageTest: ImageTest) }
Databse.kt
import android.arch.persistence.room.Database import android.arch.persistence.room.RoomDatabase import android.arch.persistence.room.TypeConverters @Database(entities = arrayOf(ImageTest::class), version = 1) @TypeConverters(DataConverters::class) abstract class Database : RoomDatabase() { abstract fun getImageTestDao(): ImageTestDao }
In DatabaseHelper something like
class DatabaseHelper(context: Context) { init { DatabaseHelper.context = WeakReference(context) } companion object { private var context: WeakReference<Context>? = null private const val DATABASE_NAME: String = "image_test_db" private var singleton: Database? = null private fun createDatabase(): Database { return Room.databaseBuilder(context?.get() ?: throw IllegalStateException("initialize by calling constructor before calling DatabaseHelper.instance"), Database::class.java, DATABASE_NAME) .build() } val instance: Database @Synchronized get() { if (null == singleton) singleton = createDatabase() return singleton as Database } fun setImage(img: Bitmap){ val dao = DatabaseHelper.instance.getImageTestDao() val imageTest = ImageTest() imageTest.data = getBytesFromImageMethod(image)//TODO dao.updsertByReplacement(imageTest) fun getImage():Bitmap?{ val dao = DatabaseHelper.instance.getImageTestDao() val imageByteArray = dao.getAll() return loadImageFromBytes(imageByteArray[0].data) //change accordingly }
Correct me if I am wrong. Hope this helps someone out there
It is usually not recommended to store image data into the database. But however if it is required for your project then you can do so.
Image data are usually stored into db using BLOB data type, Room also provide support for BLOB data type Documentation
You can declare your entity class as mentioned below to store Image data.
@Entity(tableName = "test")
public class Test{
@PrimaryKey
@ColumnInfo(name = "_id")
private int id;
@ColumnInfo(typeAffinity = ColumnInfo.BLOB)
private byte[] image;
}
As seen in CameraX's image capture use case, when a photo is successfully taken, the File path reference Uri, savedUri
, can be retrieved safely.
Then, the Uri can be converted to a string with savedUri.toString()
, and saved to Room.
Uri.parse(someString)
.In the CameraX sample, an image path's Uri can safely be obtained in onImageSaved
.
Getting Started with CameraX > 5. Implement ImageCapture use case
private fun takePhoto() {
// Get a stable reference of the modifiable image capture use case
val imageCapture = imageCapture ?: return
// Create time-stamped output file to hold the image
val photoFile = File(
outputDirectory,
SimpleDateFormat(FILENAME_FORMAT, Locale.US
).format(System.currentTimeMillis()) + ".jpg")
// Create output options object which contains file + metadata
val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()
// Set up image capture listener, which is triggered after photo has
// been taken
imageCapture.takePicture(
outputOptions, ContextCompat.getMainExecutor(this), object : ImageCapture.OnImageSavedCallback {
override fun onError(exc: ImageCaptureException) {
Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
}
override fun onImageSaved(output: ImageCapture.OutputFileResults) {
val savedUri = Uri.fromFile(photoFile)
val msg = "Photo capture succeeded: $savedUri"
Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
Log.d(TAG, msg)
}
})
}
This strategy is outlined in Saving image in Room database on Reddit.
Creating a file for the image and saving the file path in Room covers local storage. In order to ensure the images are saved across multiple devices or when if data cache and data are cleared, a form of Cloud Storage is needed to upload the files to and to download and sync with the local storage.