Home > Software design >  java.lang.RuntimeException: Exception while computing database live data
java.lang.RuntimeException: Exception while computing database live data

Time:07-24

I learning Room library for creating apps with sqlite database, but I get an error. In the first launching when I add item to DB, it navigate to fragment with RecyclerView and after 1 second my app crashes.

Error

E/SQLiteQuery: exception: Row too big to fit into CursorWindow requiredPos=0, totalRows=1; query: SELECT * FROM vet_product ORDER BY id ASC
E/AndroidRuntime: FATAL EXCEPTION: arch_disk_io_0
    Process: com.dimon.vetdatabasemobile, PID: 26700
    java.lang.RuntimeException: Exception while computing database live data.
        at androidx.room.RoomTrackingLiveData$1.run(RoomTrackingLiveData.java:92)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:923)
     Caused by: android.database.sqlite.SQLiteBlobTooBigException: Row too big to fit into CursorWindow requiredPos=0, totalRows=1
        at android.database.sqlite.SQLiteConnection.nativeExecuteForCursorWindow(Native Method)
        at android.database.sqlite.SQLiteConnection.executeForCursorWindow(SQLiteConnection.java:1001)
        at android.database.sqlite.SQLiteSession.executeForCursorWindow(SQLiteSession.java:838)
        at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:62)
        at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:153)
        at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:140)
        at com.dimon.vetdatabasemobile.db.dao_s.ProductDao_Impl$5.call(ProductDao_Impl.java:172)
        at com.dimon.vetdatabasemobile.db.dao_s.ProductDao_Impl$5.call(ProductDao_Impl.java:163)
        at androidx.room.RoomTrackingLiveData$1.run(RoomTrackingLiveData.java:90)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
        at java.lang.Thread.run(Thread.java:923) 

My models

@Parcelize
@Entity(tableName = "vet_product")
data class Product(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    val productName: String,
    val productPrice: Double,
    val productImage: Bitmap
) : Parcelable


@Parcelize
@Entity(tableName = "cart")
data class CartModel(
    @PrimaryKey(autoGenerate = true) val id: Long = 0,
    val productName: String,
    val productPrice: Double
) : Parcelable

My DAOs

@Dao
interface ProductDao {

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    fun insert(product: Product)

    @Delete
    fun delete(product: Product)

    @Update
    fun update(product: Product)

    @Query("DELETE FROM vet_product")
    fun deleteAll()

    @Query("SELECT * FROM vet_product ORDER BY id ASC")
    fun getAllProducts(): LiveData<List<Product>>

}


@Dao
interface CartDao {

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    fun insertToCart(cartModel: CartModel)

    @Query("DELETE FROM cart")
    fun deleteAllFromCart()

    @Query("SELECT * FROM cart ORDER BY id ASC")
    fun getCartModels(): LiveData<List<CartModel>>

}

My repositories

class ProductRepository(private val productDao: ProductDao) {

    val getAllProduct: LiveData<List<Product>> = productDao.getAllProducts()

    fun addProduct(product: Product) {
        productDao.insert(product)
    }

    fun updateProduct(product: Product) {
        productDao.update(product)
    }

    fun deleteProduct(product: Product) {
        productDao.delete(product)
    }

    fun deleteAllProducts() {
        productDao.deleteAll()
    }

}


class CartRepository(private val cartDao: CartDao) {

    val getAllCartModels: LiveData<List<CartModel>> = cartDao.getCartModels()

    fun addToCart(cartModel: CartModel) {
        cartDao.insertToCart(cartModel)
    }

    fun deleteAllFromCart() {
        cartDao.deleteAllFromCart()
    }

}

My viewmodels

class ProductViewModel(application: Application) : AndroidViewModel(application) {

    val getAllProducts: LiveData<List<Product>>
    private val repository: ProductRepository

    init {
        val productDao = VetDatabase.getInstance(application).productDao()

        repository = ProductRepository(productDao)
        getAllProducts = repository.getAllProduct
    }

    fun addProduct(product: Product) {
        viewModelScope.launch(Dispatchers.IO) {
            repository.addProduct(product)
        }
    }

    fun updateProduct(product: Product) {
        viewModelScope.launch(Dispatchers.IO) {
            repository.updateProduct(product)
        }
    }

    fun deleteProduct(product: Product) {
        viewModelScope.launch(Dispatchers.IO) {
            repository.deleteProduct(product)
        }
    }

    fun deleteAllProducts() {
        viewModelScope.launch(Dispatchers.IO) {
            repository.deleteAllProducts()
        }
    }

}


class CartViewModel(application: Application) : AndroidViewModel(application) {

    val getCartModels: LiveData<List<CartModel>>
    private val repository: CartRepository

    init {
        val cartDao = VetDatabase.getInstance(application).cartDao()

        repository = CartRepository(cartDao)
        getCartModels = repository.getAllCartModels
    }

    fun addToCart(cartModel: CartModel) {
        viewModelScope.launch(Dispatchers.IO) {
            repository.addToCart(cartModel)
        }
    }

    fun deleteAllFromCart() {
        viewModelScope.launch(Dispatchers.IO) {
            repository.deleteAllFromCart()
        }
    }

}

My DB

@Database(entities = [Product::class, CartModel::class], version = 5, exportSchema = false)
@TypeConverters(Converters::class)
abstract class VetDatabase : RoomDatabase() {

    abstract fun productDao(): ProductDao
    abstract fun cartDao(): CartDao

    companion object {
        @Volatile
        private var INSTANCE: VetDatabase? = null

        fun getInstance(context: Context): VetDatabase {
            val tempInstance = INSTANCE
            if (tempInstance != null) {
                return tempInstance
            }

            synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    VetDatabase::class.java,
                    "vet_db"
                )
                    .fallbackToDestructiveMigration()
                    .allowMainThreadQueries()
                    .build()

                INSTANCE = instance
                return instance
            }
        }
    }

}

But I noticed that problem with images. With some images item adds to DB succesfully but with other images it adds with crashing. I don't know how to fix this, in the Internet I found nothing. Maybe someone knows how to fix this error?

In advance thanks fow helping!

CodePudding user response:

You issue is that as described as per Row too big to fit into CursorWindow requiredPos=0, totalRows=1

Although you have successfully stored the data, it is too large for extraction. A CursorWindow MUST be able to store at least 1 full row.

  • CursorWindows have a storage limit between 1Mb and 4Mb (dependant upon the device and it's API/version).

Images, such as bitmaps, are frequently larger than the limit. It is inadvisable to store images in a database.

The recommendation is to store the image as a file and to then store the path or enough of the path to discern the image from others in the database.

  • There are ways that the data can be accessed, such as in chunks. E.g. you could extract the length of the column and then extract parts and combine them. However, such methods are not recommended as they would very likely be inefficient.
  • Related