question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Coroutine issue / IllegalStateException: View ID [...] for 'view' not found

See original GitHub issue

Disclaimer: Hi, I’ve been using Groupie for the past year, but it is kind of abandoned and EVERYBODY always says good things about epoxy, so I’m here trying to use it and breaking my head. One advice, your examples are really poor, there is 1 for java, 1 for kotlin, and 1 for paging. FastAdapter has like dozens of samples, Groupie itself has a very very complete sample. Wiki is really vague on a few things, like when to use withModels/epoxyController and which kind of ViewHolder is more efficient - there is a comment on KotlinModel saying it is not efficient, and another one on EpoxyModelWithHolder saying it is good. Makes a lot of confusion.

Anyway: I have this code (simplified) in Groupie:

class RowItem(val app: App) : Item(), CoroutineScope {

    private var job: Job = Job()
    override val coroutineContext: CoroutineContext = Dispatchers.Main + job

    override fun unbind(holder: ViewHolder) {
        job.cancel()
        holder.icon.setImageDrawable(null)
        holder.bottom_view.background = null
        super.unbind(holder)
    }

    private val bottomShape = createShape(app.backgroundColor.darken, true)
    private var drawable: Bitmap? = null

    override fun getLayout() = R.layout.row_navigation_item

    override fun bind(viewHolder: ViewHolder, position: Int) {

        viewHolder.label.setTextAsync(app.title)
        viewHolder.bottom_view.background = bottomShape

        job = Job()
        launch {
            cacheDrawable() // PAY ATTENTION TO THIS
            viewHolder.icon?.setImageBitmap(drawable)
        }
    }

    private suspend inline fun cacheDrawable() {
        if (drawable == null) {
            drawable = withContext(Dispatchers.IO) {
                AppManager.getIconFromId(app.packageName)?.toBitmap()
            }
        }
    }
}

So I went ahead and converted it to Epoxy, following your samples:

internal class PhotoController : TypedEpoxyController<List<App>>() {

    override fun buildModels(data: List<App>) {
        data.forEach {
            ItemDataClass(it)
                .id("data class \${app.packageName}")
                .addTo(this)
        }
    }
}
abstract class KotlinModel(
    @LayoutRes private val layoutRes: Int
) : EpoxyModel<View>(), CoroutineScope {

    private var job: Job = Job()
    override val coroutineContext: CoroutineContext = Dispatchers.Main + job

    override fun bind(view: View) {
        job = Job()
        this.view = view
        bind()
    }

    override fun unbind(view: View) {
        job.cancel()
        this.view = null
    }
	// everything else is same as the sample
}
data class ItemDataClass(
    val app: App, val sdkVersion: Int, val lastUpdateTime: String, val cornerRadius: Float
) : KotlinModel(R.layout.row_navigation_item) {

    val icon by bind<ImageView>(R.id.icon)
    val label by bind<AppCompatTextView>(R.id.label)
    val bottom_view by bind<View>(R.id.bottom_view)

    private val bottomShape = createShape(app.backgroundColor.darken, true)
    private var drawable: Bitmap? = null

    override fun bind() {
        label.setTextAsync(app.title)
        bottom_view.background = bottomShape

        launch {
            updateDrawable() // PAY ATTENTION TO THIS
            icon.setImageBitmap(drawable)
        }
    }

    private suspend inline fun updateDrawable() {
        if (drawable == null) {
            drawable = withContext(Dispatchers.IO) {
                AppManager.getIconFromId(app.packageName)?.toBitmap()
            }
        }
    }
}

Did you see the issue already? If I scroll very fast, by using the coroutines (since I don’t want to retrieve a drawable in main thread), when it is done, I believe icon might be null and it explodes with a IllegalStateException because getValue returns null for the view id.

It works perfectly with Groupie and the default RecyclerView. So, my question is, what should I do? Should I just go with viewBinding and forget this?

I am using 3.0.0-rc01.

Edit:

I just converted to DataBinding and… worked fine but first run got REALLY slow (like, from 1~2seconds to 6) since it is not parsing the images async - I don’t need to load them all, if it fetches them as the user scrolls is ok. Is there any strategies to fix this?

Edit 2: (again, almost no samples, which is bad) how are you using glide with it? 🤔

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:7 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
bernaferraricommented, Oct 19, 2018

You could link those two sections, I think would help a lot of people. I wouldn’t know if you haven’t linked it, thanks!

1reaction
bernaferraricommented, Oct 19, 2018

Well well, at the end of the day and with a lot of effort, everything is working perfectly! Thanks for all the help!!

Read more comments on GitHub >

github_iconTop Results From Across the Web

java.lang.IllegalStateException when collecting flow from ...
In your case the issue is probably, because of the state is captured in a coroutine invoked outside composition. Share.
Read more >
Use common Kotlin patterns with Android
This implies that when you obtain an instance of a class, you can immediately reference any of its accessible properties. The View objects...
Read more >
Gradle Managed Virtual Devices failing in CI (GitHub Actions ...
So running 'emulator -avd your_avd_name -gpu swiftshader_indirect -verbose -show-kernel' doesn't work because of the missing display inside ssh ...
Read more >
A Bottom-Up View of Kotlin Coroutines - InfoQ
This article presents a view of coroutines from the bottom up, in the hope that this will provide such a foundation.
Read more >
7 Gotchas When Explore Kotlin Coroutine | by Elye - Medium
Some are documented (I found them later), and some are not (or at least I… ... Android cannot print coroutine id name by...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found