TeamTalk5 icon indicating copy to clipboard operation
TeamTalk5 copied to clipboard

IllegalStateException in ListView from TextMessageAdapter

Open bear101 opened this issue 1 year ago • 3 comments

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)

bear101 avatar Mar 25 '24 18:03 bear101

@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()

bear101 avatar Mar 25 '24 19:03 bear101

@beqabeqa473 do you have an idea why we're getting this error?

bear101 avatar Mar 26 '24 19:03 bear101

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?

poretsky avatar Mar 27 '24 05:03 poretsky

I've been unable to reproduce the issue using Samsung A10 (API 30), Pixel 7 Pro (simulator API 34), Pixel 5 (simulator API 29)

bear101 avatar Mar 27 '24 06:03 bear101

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.

poretsky avatar Mar 27 '24 15:03 poretsky

Another solution is to keep a copy of the messages list in the adapter.

poretsky avatar Mar 27 '24 16:03 poretsky

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

bear101 avatar Mar 27 '24 20:03 bear101

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.

poretsky avatar Mar 27 '24 21:03 poretsky