Edit
I've created a demo project on Github
showing the exact problem. Git Project.
I've written an expandable recyclerView
in Kotlin
Every row has a play button which uses TextToSpeech
. The text of the play button should change to stop whilst its playing, then change back to play when it finishes.
When I call notifyItemChanged
within onStart
and onDone
of setOnUtteranceProgressListener
, onBindViewHolder
is not called and the rows in the recyclerView will no longer expand and collapse correctly.
t1 = TextToSpeech(context, TextToSpeech.OnInitListener { status ->
if (status != TextToSpeech.ERROR) {
t1?.setOnUtteranceProgressListener(object : UtteranceProgressListener() {
override fun onStart(utteranceId: String?) {
recyclerView.adapter.notifyItemChanged(position)
}
override fun onStop(utteranceId: String?, interrupted: Boolean) {
super.onStop(utteranceId, interrupted)
onDone(utteranceId)
}
override fun onDone(utteranceId: String?) {
val temp = position
position = -1
recyclerView.adapter.notifyItemChanged(temp)
}
override fun onError(utteranceId: String?) {}
// override fun onError(utteranceId: String?, errorCode: Int) {
// super.onError(utteranceId, errorCode)
// }
})
}
})
onBindViewHolder:
override fun onBindViewHolder(holder: RabbanaDuasViewHolder, position: Int){
if (Values.playingPos == position) {
holder.cmdPlay.text = context.getString(R.string.stop_icon)
}
else {
holder.cmdPlay.text = context.getString(R.string.play_icon)
}
}
How can I call notifyItemChanged(position)
from within setOnUtteranceProgressListener
or what callback can I use so that notifyItemChanged only executes when it's safe to execute?
I tried to replicate your issue and I came to know that it is not working because methods of UtteranceProgressListener
is not called on main thread and that's why onBindViewHolder
method of the adapter is not called.
This worked for me and should work for you too:
Use runOnUiThread{}
method to perform actions on RecyclerView
like this:
t1.setOnUtteranceProgressListener(object : UtteranceProgressListener() {
override fun onError(utteranceId: String?) {
}
override fun onStart(utteranceId: String?) {
runOnUiThread {
recyclerView.adapter?.notifyItemChanged(position)
}
}
override fun onStop(utteranceId: String?, interrupted: Boolean) {
super.onStop(utteranceId, interrupted)
onDone(utteranceId)
}
override fun onDone(utteranceId: String?) {
val temp = position
position = -1
runOnUiThread {
recyclerView.adapter?.notifyItemChanged(temp)
}
}
}
I solved the problem using runOnUiThread
thanks to Birju Vachhani.
For a full working demo of not just the problem I had, but how to correctly expand and collapse rows in a RecyclerView
(no onClick
events in onBindViewHolder
) see my Gitlab Demo Project.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With