START EDIT scroll down updated code END OF EDIT
I have google and search around SO why this exception occurs, and I understand that this is caused by the object reading the list, and meanwhile the element has been removed from the list.
I changed my code according to the suggestions I found, but from time to time I still get this exception and this is a crash of my application. And it looks random, I try to replicate the exception, and 90% of the time I do not get the exception and do not always follow the same procedure, which makes debugging difficult.
I use the observer pattern. Sometimes this happens with a method unregister, some others with register, in other cases with a method from notify... this is a rather random case when this happens.
I use android asynctaskto download several bytes from my server, and the observer pattern - if necessary, update the GUI.
Here is my code:
@Override
public void register(final Observer newObserver) {
Log.d(TAG, "(Register) Observer registred: " + newObserver.toString());
observers.add(newObserver);
Log.d(TAG, "(Register) Number of registered observers: " + observers.size());
}
@Override
public void unregister(final Observer observer) {
int indexObersver = observers.indexOf(observer);
if(indexObersver >= 0)
{
observers.remove(indexObersver);
Log.d(TAG, "(Unregister) Unregistered Observer: " + observer.toString());
Log.d(TAG, "(Unregister) Now we have: " + observers.size() + " observers");
}
else
{
Log.d(TAG, "(Unregister) Registered Observer not found");
}
}
@Override
public void notifyObserverNewLocalBackup(BackupInfo backupInfo) {
for( Iterator< Observer > it = observers.iterator(); it.hasNext() ; )
{
Observer observer = it.next();
observer.notifyNewLocalBackup(backupInfo);
}
}
@Override
public void notifyObserverNewRemoteBackup(ArrayList<PhoneBackup> phoneBackups) {
for( Iterator< Observer > it = observers.iterator(); it.hasNext() ; )
{
Observer observer = it.next();
observer.notifyNewRemoteBackup(phoneBackups);
}
}
@Override
public void notifyObserverDownloadCompleted(PhoneBackup phoneBackup) {
for( Iterator< Observer > it = observers.iterator(); it.hasNext() ; )
{
Observer observer = it.next();
observer.notifyDownloadCompleted(phoneBackup);
}
}
@Override
public void notifyObserverUploadCompleted(boolean isSucccess) {
for( Iterator< Observer > it = observers.iterator(); it.hasNext() ; )
{
Observer observer = it.next();
observer.notifyUploadCompleteted(isSucccess);
}
}
Now, for the last time, it turned out that this happened according to the method notifyObserverNewRemoteBackupin the lineObserver observer = it.next();
06-12 04:31:58.394: W/dalvikvm(31358): threadid=1: thread exiting with uncaught exception (group=0x418fcce0)
06-12 04:31:58.629: E/AndroidRuntime(31358): FATAL EXCEPTION: main
06-12 04:31:58.629: E/AndroidRuntime(31358): Process: com.mypackage.android.design.appdesgin, PID: 31358
06-12 04:31:58.629: E/AndroidRuntime(31358): java.util.ConcurrentModificationException
06-12 04:31:58.629: E/AndroidRuntime(31358): at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:573)
06-12 04:31:58.629: E/AndroidRuntime(31358): at com.mypackage.android.design.appdesgin.asynctasks.ObserverSubjectManager.notifyObserverNewRemoteBackup(ObserverSubjectManager.java:99)
06-12 04:31:58.629: E/AndroidRuntime(31358): at com.mypackage.android.design.appdesgin.asynctasks.BackupsHandler$1.success(BackupsHandler.java:318)
06-12 04:31:58.629: E/AndroidRuntime(31358): at com.mypackage.android.design.appdesgin.asynctasks.BackupsHandler$1.success(BackupsHandler.java:1)
06-12 04:31:58.629: E/AndroidRuntime(31358): at retrofit.CallbackRunnable$1.run(CallbackRunnable.java:45)
06-12 04:31:58.629: E/AndroidRuntime(31358): at android.os.Handler.handleCallback(Handler.java:733)
06-12 04:31:58.629: E/AndroidRuntime(31358): at android.os.Handler.dispatchMessage(Handler.java:95)
06-12 04:31:58.629: E/AndroidRuntime(31358): at android.os.Looper.loop(Looper.java:136)
06-12 04:31:58.629: E/AndroidRuntime(31358): at android.app.ActivityThread.main(ActivityThread.java:5081)
06-12 04:31:58.629: E/AndroidRuntime(31358): at java.lang.reflect.Method.invokeNative(Native Method)
06-12 04:31:58.629: E/AndroidRuntime(31358): at java.lang.reflect.Method.invoke(Method.java:515)
06-12 04:31:58.629: E/AndroidRuntime(31358): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
06-12 04:31:58.629: E/AndroidRuntime(31358): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:607)
06-12 04:31:58.629: E/AndroidRuntime(31358): at dalvik.system.NativeStart.main(Native Method)
---------------------- EDIT --------------------- ------ ----
I followed the Anubian Noob suggestion and I implemented a synchronized list, but I still get the exception.
Here is my updated code:
public synchronized static ObserverSubjectManager getInstance()
{
if(instance == null)
{
instance = new ObserverSubjectManager();
return instance;
}
return instance;
}
private ObserverSubjectManager()
{
observers = Collections.synchronizedList(new ArrayList<Observer>());
}
@Override
public void register(final Observer newObserver) {
Log.d(TAG, "(Register) Observer registred: " + newObserver.toString());
synchronized (observers) {
observers.add(newObserver);
}
Log.d(TAG, "(Register) Number of registered observers: " + observers.size());
}
@Override
public void unregister(final Observer observer) {
synchronized (observers)
{
int indexObersver = observers.indexOf(observer);
if(indexObersver >= 0)
{
observers.remove(indexObersver);
Log.d(TAG, "(Unregister) Unregistered Observer: " + observer.toString());
Log.d(TAG, "(Unregister) Now we have: " + observers.size() + " observers");
}
else
{
Log.d(TAG, "(Unregister) Registered Observer not found");
}
}
}
@Override
public void notifyObserverNewLocalBackup(final BackupInfo backupInfo) {
synchronized (observers)
{
for(Observer observer : observers)
{
observer.notifyNewLocalBackup(backupInfo);
}
}
}
@Override
public void notifyObserverNewRemoteBackup(final ArrayList<PhoneBackup> phoneBackups) {
synchronized (observers)
{
for(Observer observer : observers)
{
observer.notifyNewRemoteBackup(phoneBackups);
}
}
}
@Override
public void notifyObserverDownloadCompleted(final PhoneBackup phoneBackup) {
synchronized (observers)
{
for(Observer observer : observers)
{
observer.notifyDownloadCompleted(phoneBackup);
}
}
}
@Override
public void notifyObserverUploadCompleted(final boolean isSucccess) {
synchronized (observers)
{
for(Observer observer : observers)
{
observer.notifyUploadCompleteted(isSucccess);
}
}
}
Stacktrace:
06-12 05:12:49.359: W/dalvikvm(31735): threadid=1: thread exiting with uncaught exception (group=0x418fcce0)
06-12 05:12:49.426: E/AndroidRuntime(31735): FATAL EXCEPTION: main
06-12 05:12:49.426: E/AndroidRuntime(31735): Process: com.mypackage.android.design.appdesgin, PID: 31735
06-12 05:12:49.426: E/AndroidRuntime(31735): java.util.ConcurrentModificationException
06-12 05:12:49.426: E/AndroidRuntime(31735): at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:573)
06-12 05:12:49.426: E/AndroidRuntime(31735): at com.mypackage.android.design.appdesgin.asynctasks.ObserverSubjectManager.notifyObserverDownloadCompleted(ObserverSubjectManager.java:126)
06-12 05:12:49.426: E/AndroidRuntime(31735): at com.mypackage.android.design.appdesgin.asynctasks.BackupsHandler$2.success(BackupsHandler.java:336)
06-12 05:12:49.426: E/AndroidRuntime(31735): at com.mypackage.android.design.appdesgin.asynctasks.BackupsHandler$2.success(BackupsHandler.java:1)
06-12 05:12:49.426: E/AndroidRuntime(31735): at retrofit.CallbackRunnable$1.run(CallbackRunnable.java:45)
06-12 05:12:49.426: E/AndroidRuntime(31735): at android.os.Handler.handleCallback(Handler.java:733)
06-12 05:12:49.426: E/AndroidRuntime(31735): at android.os.Handler.dispatchMessage(Handler.java:95)
06-12 05:12:49.426: E/AndroidRuntime(31735): at android.os.Looper.loop(Looper.java:136)
06-12 05:12:49.426: E/AndroidRuntime(31735): at android.app.ActivityThread.main(ActivityThread.java:5081)
06-12 05:12:49.426: E/AndroidRuntime(31735): at java.lang.reflect.Method.invokeNative(Native Method)
06-12 05:12:49.426: E/AndroidRuntime(31735): at java.lang.reflect.Method.invoke(Method.java:515)
06-12 05:12:49.426: E/AndroidRuntime(31735): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
06-12 05:12:49.426: E/AndroidRuntime(31735): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:607)
06-12 05:12:49.426: E/AndroidRuntime(31735): at dalvik.system.NativeStart.main(Native Method)