【发布时间】:2019-08-30 12:32:09
【问题描述】:
我在我的应用程序中使用 Room 作为单一数据源,因此来自后端的所有内容都保存在我的房间数据库中,然后返回一个 Flowable,每次数据更改时都会触发一个事件。这是我的 PlacesDAO:
@Dao
abstract class PlacesDao {
@Query("select * from places where placeId = :id")
abstract fun getPlace(id: String): Flowable<PlaceVO>
@Query("select * from places where placeId in (:placesIds) order by distance, placeName ASC")
abstract fun getPlaces(placesIds: List<String>): Flowable<List<PlaceVO>>
@Query("select * from places join list_results where Places.placeId = list_results.id order by distance, placeName ASC")
abstract fun getFilteredPlaces(): Flowable<List<PlaceVO>>
@Query("select * from places join user_places where Places.placeId = user_places.placeId AND user_places.userId = :userId order by distance, placeName ASC ")
abstract fun getAllByUser(userId: String) : Flowable<List<PlaceVO>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun realSavePlaces(places:List<PlaceVO>)
fun savePlaces(places: List<PlaceVO>){
Timber.w("PAGELIST - Saving places again!!")
realSavePlaces(places)
}
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun savePlace(place: PlaceVO)
@Query("DELETE from places")
abstract fun deleteAll()
@Query("select * from places")
abstract fun getAll(): Single<List<PlaceVO>>
@Query("select * from places where (experienceId IS NOT NULL) AND (experienceId != '') order by placeName")
abstract fun getMyPlaces(): Flowable<List<PlaceVO>>
@Query("update places set distance = :distance and distanceSet = 1 where placeId = :id")
abstract fun updateDistance(id: String, distance: Float)
}
现在,在我的应用中,有一些操作会触发更改此表中的数据,这会导致我的 UI 接收表中包含的所有项目(大约 3000-5000)。
它并不总是发生(这使得它难以重现),但我会时不时地遇到以下崩溃:
Caused by android.database.sqlite.SQLiteBlobTooBigException: Row too big to fit into CursorWindow requiredPos=1223, totalRows=114
at android.database.sqlite.SQLiteConnection.nativeExecuteForCursorWindow(SQLiteConnection.java)
at android.database.sqlite.SQLiteConnection.executeForCursorWindow + 895(SQLiteConnection.java:895)
at android.database.sqlite.SQLiteSession.executeForCursorWindow + 836(SQLiteSession.java:836)
at android.database.sqlite.SQLiteQuery.fillWindow + 62(SQLiteQuery.java:62)
at android.database.sqlite.SQLiteCursor.fillWindow + 157(SQLiteCursor.java:157)
at android.database.sqlite.SQLiteCursor.onMove + 128(SQLiteCursor.java:128)
at android.database.AbstractCursor.moveToPosition + 237(AbstractCursor.java:237)
at android.database.AbstractCursor.moveToNext + 269(AbstractCursor.java:269)
at com.myapp.android.model.db.dao.PlacesDao_Impl$6.call + 814(PlacesDao_Impl.java:814)
at com.myapp.android.model.db.dao.PlacesDao_Impl$6.call + 771(PlacesDao_Impl.java:771)
at io.reactivex.internal.operators.maybe.MaybeFromCallable.subscribeActual + 46(MaybeFromCallable.java:46)
at io.reactivex.Maybe.subscribe + 4262(Maybe.java:4262)
at io.reactivex.internal.operators.flowable.FlowableFlatMapMaybe$FlatMapMaybeSubscriber.onNext + 132(FlowableFlatMapMaybe.java:132)
at io.reactivex.internal.operators.flowable.FlowableObserveOn$ObserveOnSubscriber.runAsync + 407(FlowableObserveOn.java:407)
at io.reactivex.internal.operators.flowable.FlowableObserveOn$BaseObserveOnSubscriber.run + 176(FlowableObserveOn.java:176)
at io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker$BooleanRunnable.run + 260(ExecutorScheduler.java:260)
at io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker.run + 225(ExecutorScheduler.java:225)
at java.util.concurrent.ThreadPoolExecutor.runWorker + 1167(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run + 641(ThreadPoolExecutor.java:641)
at java.lang.Thread.run + 764(Thread.java:764)
我只存储文本信息,正如这个类所证明的那样:
@Entity(tableName = "places")
data class PlaceVO(
@PrimaryKey
var placeId: String,
var googleId: String,
var placeName: String,
var phoneNumber: String,
@Embedded
var primaryCategory: Category?,
var primaryCategoryTags: List<CategoryTag> = emptyList(),
var secondaryCategories: List<Category>? = emptyList(),
var images: List<Image>,
var website: String,
var formattedAddress: String? = "",
var vicinity: String = "",
var vicinityShort: String = "",
var city: String? = "",
var neighbourhood: String?,
var longitude: Double,
var latitude: Double,
var openingHours: List<String>,
var combinedHighlights: List<HighlightCountWrapper>,
@Embedded
var ownExperience: OwnExperience?,
var otherExperiences: List<Experience>,
var distance: Float?,
var distanceSet: Boolean = false,
var comment: String
) : MarkerPlace {
}
体验课:
@Entity
data class Experience(
@Json(name="id")
val experienceId: String,
@Embedded
val owner: User,
val description: String?,
val highlights: List<Highlight>?,
val images: List<Image> = emptyList(),
val createdDate: Date,
val updatedDate: Date,
var privacyLevel: AddExperience.Privacy? = null)
一些类型转换器:
@TypeConverter
fun toHighlightWrapperList(value: String): List<HighlightCountWrapper> {
val type = Types.newParameterizedType(List::class.java, HighlightCountWrapper::class.java)
return moshi.adapter<List<HighlightCountWrapper>>(type).fromJson(value) ?: emptyList()
}
@TypeConverter
fun fromHighlightWrapperList(list: List<HighlightCountWrapper>): String {
val type = Types.newParameterizedType(List::class.java, HighlightCountWrapper::class.java)
var adapter: JsonAdapter<List<HighlightCountWrapper>> = moshi.adapter<List<HighlightCountWrapper>>(type)
return adapter.toJson(list)
}
@TypeConverter
fun toExperienceList(value: String): List<Experience> {
val type = Types.newParameterizedType(List::class.java, Experience::class.java)
return moshi.adapter<List<Experience>>(type).fromJson(value) ?: emptyList()
}
@TypeConverter
fun fromExperienceList(list: List<Experience>): String {
val type = Types.newParameterizedType(List::class.java, Experience::class.java)
var adapter: JsonAdapter<List<Experience>> = moshi.adapter<List<Experience>>(type)
return adapter.toJson(list)
}
@TypeConverter
fun toImageList(value: String): List<Image> {
val type = Types.newParameterizedType(List::class.java, Image::class.java)
return moshi.adapter<List<Image>>(type).fromJson(value) ?: emptyList()
}
@TypeConverter
fun fromImageList(list: List<Image>): String {
val type = Types.newParameterizedType(List::class.java, Image::class.java)
var adapter: JsonAdapter<List<Image>> = moshi.adapter<List<Image>>(type)
return adapter.toJson(list)
}
那么我的行怎么可能对 SQLite 来说太大了?尤其是有时会毫无问题地返回完全相同的数据?
【问题讨论】:
-
"那么我的行怎么可能对 SQLite 来说太大了?" -- 大小限制为 1MB,IIRC。你有很多
List属性,包括两个看起来很吓人的List<Image>。 “尤其是有时会毫无问题地返回完全相同的数据?” -- 这可能取决于查询中返回的其他内容。 -
将它们建模为单独的实体而不是将它们字符串化为 json 会使问题变得更好吗?
-
显然对我来说这只发生在
onePlus设备上
标签: android android-room