Search code examples
androidkotlinandroid-roomtypeconverter

Error when trying to save bitmap to room database with TypeConverter


I'm currently trying to save a bitmap image to a ROOM db, but I keep getting this error when I try to run my app.

> Task :app:kaptDebugKotlin
C:\Users\xinyu\AndroidStudioProjects\Red\app\build\tmp\kapt3\stubs\debug\com\google\gradient\red\data\models\JournalData.java:20: error: Cannot figure out how to save this field into database. You can consider adding a type converter for it.
    private android.graphics.Bitmap image;
                                    ^[WARN] Incremental annotation processing requested, but support is disabled because the following processors are not incremental: androidx.room.RoomProcessor (DYNAMIC).

From looking at other StackOverflow questions, it looks like the problem I'm having is that I'm using the wrong types, but I'm not sure how I would change my converters to make this work. Any help would be greatly appreciated!

Here is my code (related parts):

Converter.kt

class Converter {

    @TypeConverter
    fun fromBitmap(bitmap: Bitmap): ByteArray {
        val outputStream = ByteArrayOutputStream()
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
        return outputStream.toByteArray()
    }

    fun toBitmap(byteArray: ByteArray): Bitmap {
        return BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size)
    }
}

UpdateFragment.kt

override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        val view = inflater.inflate(R.layout.fragment_update, container, false)

        // set menu
        setHasOptionsMenu(true)

        view.current_title_et.setText(args.currentItem.title)
        view.current_description_et.setText(args.currentItem.description)
        view.current_mood_spinner.setSelection(mSharedViewModel.parseMood(args.currentItem.mood))
        view.current_mood_spinner.onItemSelectedListener = mSharedViewModel.listener

        // Opens gallery when image button clicked, gets image
        view.current_image_et.setOnClickListener {
            val intent = Intent(Intent.ACTION_PICK)
            intent.type = "image/*"
            startActivityForResult(intent, 1218)
        }

        return view
    }

    // Handle result of picked image
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        if (resultCode == Activity.RESULT_OK && requestCode == 1001) {

            // Converts image URI to bitmap
            if (data != null && data.data != null) {
                val uri = data.data!!
                val inputStream = requireContext().contentResolver.openInputStream(uri)
                val cursor = requireContext().contentResolver.query(uri, null, null, null, null)
                cursor?.use { c ->
                    val nameIndex = c.getColumnIndex(OpenableColumns.DISPLAY_NAME)
                    if (c.moveToFirst()) {
                        val name = c.getString(nameIndex)
                        inputStream?.let { inputStream ->
                            // create same file with same name
                            val file = File(requireContext().cacheDir, name)
                            val os = file.outputStream()
                            os.use {
                                inputStream.copyTo(it)
                            }
                            bitmap = BitmapFactory.decodeFile(file.absolutePath)
                            preview_image.setImageBitmap(bitmap)
                        }
                    }
                }
            }
        }
    }

Solution

  • I figured out the issue.

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

    I forgot to add a @TypeConverter annotation to my toBitmap function.