如何在房间持久性库中插入图像?
Posted
技术标签:
【中文标题】如何在房间持久性库中插入图像?【英文标题】:How insert image in room persistence library? 【发布时间】:2018-03-02 10:15:55 【问题描述】:我正在为我的 android 应用程序使用房间持久性库,现在我必须在我的数据库中插入图像。我成功地为原始数据类型定义了@Entity。并且还通过转换器类,我存储了所有对象、日期、时间。现在我必须存储图像。我无法理解我们如何定义列信息和实体,以及我们如何插入该数据以及如何从表中读取数据。
插入单行的最大数据大小是多少? Android SQLite 中一个字段中数据的最大和最小大小是多少?
【问题讨论】:
您可以使用 blob 将图像存储在 Room 中。 关注developer.android.com/topic/libraries/architecture/room.html @CommonsWare 如果您不建议将图像存储在数据库中,您有什么建议?将图像存储在外部存储中? @Aniruddha:使用internal storage还是external storage取决于用户是否需要独立访问图像。 @CommonsWare 如果您能解释为什么不建议将图像存储在数据库中,那将是最好的学习目的。 【参考方案1】:通常不建议将图像数据存储到数据库中。 但是,如果您的项目需要它,那么您可以这样做。
图像数据通常使用BLOB数据类型存储到db中,Room也提供对BLOB数据类型的支持Documentation
您可以如下所述声明您的实体类来存储图像数据。
@Entity(tableName = "test")
public class Test
@PrimaryKey
@ColumnInfo(name = "_id")
private int id;
@ColumnInfo(typeAffinity = ColumnInfo.BLOB)
private byte[] image;
【讨论】:
感谢它的工作。我需要添加将原始图像转换为 byte[] 和 byte[] 为原始图像的编码器和解码器 @PrinceKumar 是的,您需要编码器和解码器将位图转换为字节 [],反之亦然。 我不能使用 Blob 类型? @JhonFredyTrujilloOrtega,如果您不想使用 blob,请先压缩图像,然后将其转换为“base 64”字符串并将其存储在数据库中。不建议存储“blob”或“base 64”。最好将文件本地存储到文件系统中,并且只在 db 中添加引用条目。不过可以满足你的要求。 这个解决方案似乎没有真正使用 BLOB。该解决方案使应用程序将字节数组完全保存在内存中,而真正的 BLOB 用户(例如在 SQLite 或 mysql 中)将使用 InputStream 进行写入,OutputStream 进行写入。因此,如果字节数组太大,一次只能在内存中保存一个缓冲区。顺便说一句,BitmapFactory 支持使用 InputStream。 ROOM 数据库是否缺少此功能?【参考方案2】:正如 Pinakin 所说,不建议将图像存储到数据库中,文件路径会更好,但如果需要存储图像,我建议将图像压缩到 2 MB 以下 (here is an example) 以避免破坏应用程序. Room 支持图像的 BLOB。 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
在 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
如果我错了,请纠正我。希望这可以帮助那里的人
【讨论】:
感谢每一行的解释和易于理解的解决方案,我在 java 中的整个项目。【参考方案3】:将图片保存为文件并将文件路径Uri保存到Room
如CameraX的image capture用例中所见,当成功拍摄照片时,文件路径引用Uri,savedUri
,可以安全取回。
然后,可以将 Uri 转换为带有savedUri.toString()
的字符串,并保存到 Room。
Uri.parse(someString)
的 Glide。
在 CameraX 示例中,可以在 onImageSaved
中安全地获取图像路径的 Uri。
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)
)
Reddit 上的Saving image in Room database 中概述了此策略。
云存储
为图像创建文件并将文件路径保存在 Room 中涵盖了本地存储。为了确保图像在多个设备上保存,或者当数据缓存和数据被清除时,需要一个 Cloud Storage 的形式将文件上传到本地存储并下载并与本地存储同步.
【讨论】:
以上是关于如何在房间持久性库中插入图像?的主要内容,如果未能解决你的问题,请参考以下文章