Status Update
Comments
da...@google.com <da...@google.com> #2
This is actually happening in a lot of cases beyond just stable IDs; that just happens to be a particularly easy case to repro it on. Running the RecyclerView test suite on the commit in aosp/2345032 (which validates the intended invariants around temp-detached ViewHolders) will reveal the full extent (thousands of failing tests).
There are two possible ways to fix this:
-
When binding a temporarily detached ViewHolder, temporarily re-attach it, perform the bind operation, then immediately temporarily detach it again. This is implemented as aosp/2366713 and passes all tests. I favor this solution, as it's very, very simple. There's not much in the way of potential to go wrong, confuse a third-party LayoutManager, have incorrect bookkeeping, etc. The only reason not to do this is that it performs more temp detaches/reattaches than is strictly necessary, though this is a sufficiently lightweight operation that we currently temp-detach every view on every layout. If this were a bottleneck, I'd think that'd be a place to look at as well.
-
When binding a temporarily detached ViewHolder, temporarily re-attach it, marking it as being temporarily reattached for binding. If the LayoutManager attaches the View manually, simply clear the flag. At the end of layout, go through the scrap views and properly handle these. I do not favor this approach, as it has many possible edge cases (for example, the LayoutManager might add the View somewhere other than the end, which isn't yet handled in the implementation). I've implemented the basics of this as aosp/2371868 as a proof of concept (though one test is currently failing—I am a bit surprised it's not more). I don't want to spend much more time on it, though, as I favor approach #1 absent a reason not to do that.
After discussion, we've decided on approach 1.
Description
room-common (androidX)
room-coroutines (androidX)
Kotlin
Version used: 2.1.0-alpha03
Devices/Android versions reproduced on: Compilation error
This issue happens when you try to make a concret Room Dao inherit from a generic Dao using coroutine (with suspend keyword on them), it displays the following error :
error: Type of the parameter must be a class annotated with @Entity or a collection/array of it.
kotlin.coroutines.Continuation<? super kotlin.Unit> p1);
^
Classes I use to reproduce this problem :
@Database(
version = 1,
entities = [
User::class
],
exportSchema = true
)
abstract class RoomDB : RoomDatabase() {
abstract fun getUserDao(): UserDao
}
@Entity(tableName = "user")
data class User(
@PrimaryKey(autoGenerate = true) val id: Long = 0,
val firstName: String,
val lastName: String
)
interface BaseDao<T> {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertOrUpdate(entity: T)
}
@Dao
interface UserDao: BaseDao<User> {
@Query("SELECT * FROM user")
suspend fun loadAll(): List<User>
}
I tried several things, like using varags in parameter on insertOrUpdate method, or giving it an output (List<Int> or Int) without any change in the error.
A sample project is in attachment to reproduce this bug.
Thank you in advance