TeamTalk5
TeamTalk5 copied to clipboard
IllegalStateException in ListView from TextMessageAdapter
Description
Google Play rejects TeamTalk for Android build 130 because of the following error:
java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(2131230864, class android.widget.ListView) with Adapter(class dk.bearware.data.TextMessageAdapter)]
Application
- [ ] qtTeamTalk
- [X] TeamTalkAndroid
- [ ] iTeamTalk
- [ ] TeamTalkClassic
- [ ] TeamTalkServer
Platform
- [ ] Windows
- [ ] macOS
- [X] Android
- [ ] iOS
- [ ] Linux
Expected behavior
ListView should be updated from UI thread
Actual behavior
ListView is updated from background thread
Steps to reproduce problem
Exception java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(2131230864, class android.widget.ListView) with Adapter(class dk.bearware.data.TextMessageAdapter)]
at android.widget.ListView.layoutChildren (ListView.java:1717)
at android.widget.ListView.setSelectionInt (ListView.java:2232)
at android.widget.AbsListView.resurrectSelection (AbsListView.java:5532)
at android.widget.AbsListView.onWindowFocusChanged (AbsListView.java:3089)
at android.view.View.dispatchWindowFocusChanged (View.java:14582)
at android.view.ViewGroup.dispatchWindowFocusChanged (ViewGroup.java:1502)
at android.view.ViewGroup.dispatchWindowFocusChanged (ViewGroup.java:1506)
at android.view.ViewGroup.dispatchWindowFocusChanged (ViewGroup.java:1506)
at android.view.ViewGroup.dispatchWindowFocusChanged (ViewGroup.java:1506)
at android.view.ViewGroup.dispatchWindowFocusChanged (ViewGroup.java:1506)
at android.view.ViewGroup.dispatchWindowFocusChanged (ViewGroup.java:1506)
at android.view.ViewGroup.dispatchWindowFocusChanged (ViewGroup.java:1506)
at android.view.ViewGroup.dispatchWindowFocusChanged (ViewGroup.java:1506)
at android.view.ViewGroup.dispatchWindowFocusChanged (ViewGroup.java:1506)
at android.view.ViewGroup.dispatchWindowFocusChanged (ViewGroup.java:1506)
at android.view.ViewRootImpl.handleWindowFocusChanged (ViewRootImpl.java:3262)
at android.view.ViewRootImpl.access$1200 (ViewRootImpl.java:194)
at android.view.ViewRootImpl$ViewRootHandler.handleMessage (ViewRootImpl.java:5053)
at android.os.Handler.dispatchMessage (Handler.java:106)
at android.os.Looper.loop (Looper.java:223)
at android.app.ActivityThread.main (ActivityThread.java:7664)
at java.lang.reflect.Method.invoke
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:947)
@poretsky Any idea what could cause this error?
Could it be because MainActivity's call to:
public void setTextMessages(Vector<MyTextMessage> msgs) {
messages = msgs;
}
.. that changes TextMessageAdapter.getCount()
@beqabeqa473 do you have an idea why we're getting this error?
No, this call is followed by notifyDataSetChanged() as it should be and onServiceConnected() callback itself works in the UI thread.
But I cannot find a clue. The backtrace cited doesn't refer to the point in the app source that caused the exception. Can it be reproduced on a device anyway?
I've been unable to reproduce the issue using Samsung A10 (API 30), Pixel 7 Pro (simulator API 34), Pixel 5 (simulator API 29)
Not having an information about exact event that caused the problem, I dare to suggest following reasons based on the available data anyway.
The textmsgAdapter in MainActivity is initialized by vector returned by TeamTalkService.getChatLogTextMsgs() method. This vector then is updated in a bunch of places in the TeamTalkService class. But this class knows nothing about connected list adapter. Some of these updates occur in the ClientEventListener callbacks and TextMessageAdapter.notifyDataSetChanged() is invoked in the corresponding callbacks in the activity. But obviously there are some updates that aren't followed by the adapter notification.
I'd suggest to introduce a callback in TeamTalkService to notify about messages list update. And some additional care can require if ClientEventListener callbacks are executed not in UI thread.
Another solution is to keep a copy of the messages list in the adapter.
So here we should call msgs.clone():
https://github.com/BearWare/TeamTalk5/blob/master/Client/TeamTalkAndroid/src/main/java/dk/bearware/data/TextMessageAdapter.java#L94
Yes. And invoke textmsgAdapter.setTextMessages(ttservice.getChatLogTextMsgs()) before textmsgAdapter.notifyDataSetChanged() in MainActivity. And in addition I'd recommend to add textmsgAdapter.notifyDataSetChanged() after textmsgAdapter.setMyUserID(my_userid) in the MainActivity.onCmdMyselfLoggedIn() method.