我正在为我的 Android 应用程序使用 Room 持久性库,现在我需要在我的数据库中插入图像。我已经成功地为原始数据类型定义了 @Entity,并且通过转换器类存储了所有对象、日期和时间。现在我需要存储图像。我不明白如何定义列信息和实体,以及如何插入该数据并从表中读取数据。
单个行插入的数据的最大大小是多少?Android SQLite 中一个字段的最小和最大数据大小是多少?
我正在为我的 Android 应用程序使用 Room 持久性库,现在我需要在我的数据库中插入图像。我已经成功地为原始数据类型定义了 @Entity,并且通过转换器类存储了所有对象、日期和时间。现在我需要存储图像。我不明白如何定义列信息和实体,以及如何插入该数据并从表中读取数据。
单个行插入的数据的最大大小是多少?Android SQLite 中一个字段的最小和最大数据大小是多少?
通常不建议将图像数据存储到数据库中。但是,如果项目需要,您可以这样做。
图像数据通常使用BLOB数据类型存储到数据库中,Room还提供对BLOB数据类型的支持。文档
您可以按照下面所示声明实体类来存储图像数据。
@Entity(tableName = "test")
public class Test{
@PrimaryKey
@ColumnInfo(name = "_id")
private int id;
@ColumnInfo(typeAffinity = ColumnInfo.BLOB)
private byte[] image;
}
正如Pinakin所提到的,不推荐将图像存储在数据库中,最好使用文件路径,但如果需要存储图像,我建议将图像压缩至2 MB以下(这里有一个示例),以避免应用程序崩溃。Room支持用于图像的BLOB。
Kotlin中的实体类:
ImageTest.kt
@Entity
class ImageTest {
@PrimaryKey(autoGenerate = true)
var id: Int = 1
@ColumnInfo(typeAffinity = ColumnInfo.BLOB)
var data: ByteArray? = null
}
@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)
}
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
}
在DatabaseHelper中,类似于以下内容:
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
}
如果我错了,请纠正我。希望这对某些人有所帮助。
如在CameraX的图像捕获用例中所示,当成功拍摄照片时,可以安全地检索到文件路径引用Uri savedUri
。
然后,可以使用savedUri.toString()
将Uri转换为字符串,并保存到Room中。
Uri.parse(someString)
。在CameraX示例中,可以在onImageSaved
中安全地获取图像路径的Uri。
开始学习CameraX > 5. 实施ImageCapture用例
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)
}
})
}
这种策略在Reddit中的在Room数据库中保存图像中有详细说明。
创建一个文件来保存图像,并将文件路径保存在Room中,可以覆盖本地存储。为了确保图像能够跨多个设备保存,或者当数据缓存和数据被清除时能够下载并与本地存储同步,需要一种形式的云存储。