【发布时间】:2014-06-12 15:46:20
【问题描述】:
开始编辑请向下滚动查看更新的代码END OF EDIT
我已经用谷歌搜索并搜索了为什么会发生此异常,我知道这是由一个对象正在读取列表而同时从列表中删除了一个项目引起的。
我已根据我找到的建议相应地更改了我的代码,但有时我仍然会收到此异常,并且它正在使我的应用程序崩溃。而且它看起来是随机的,我尝试复制异常,并且 90% 的时间我没有得到异常,并且并不总是遵循相同的过程,这使得调试变得困难。
我正在使用观察者模式。有时使用unregister 方法,有时使用register,有时使用notify 中的方法......它发生的位置非常随机。
我正在使用 android asynctask 从我的服务器下载几个字节,观察者模式是在需要时更新 GUI。
这是我的代码:
@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);
// Avoid java.util.ConcurrentModificationException
// at java.util.ArrayList$ArrayListIterator.next(ArrayList.java)
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) {
// Avoid java.util.ConcurrentModificationException
// at java.util.ArrayList$ArrayListIterator.next(ArrayList.java)
for( Iterator< Observer > it = observers.iterator(); it.hasNext() ; )
// for(Observer observer : observers)
{
Observer observer = it.next();
observer.notifyNewLocalBackup(backupInfo);
}
}
@Override
public void notifyObserverNewRemoteBackup(ArrayList<PhoneBackup> phoneBackups) {
// Avoid java.util.ConcurrentModificationException
// at java.util.ArrayList$ArrayListIterator.next(ArrayList.java)
// for(Observer observer : observers)
for( Iterator< Observer > it = observers.iterator(); it.hasNext() ; )
{
Observer observer = it.next();
observer.notifyNewRemoteBackup(phoneBackups);
}
}
@Override
public void notifyObserverDownloadCompleted(PhoneBackup phoneBackup) {
// Avoid java.util.ConcurrentModificationException
// at java.util.ArrayList$ArrayListIterator.next(ArrayList.java)
// for(Observer observer : observers)
for( Iterator< Observer > it = observers.iterator(); it.hasNext() ; )
{
Observer observer = it.next();
observer.notifyDownloadCompleted(phoneBackup);
}
}
@Override
public void notifyObserverUploadCompleted(boolean isSucccess) {
// Avoid java.util.ConcurrentModificationException
// at java.util.ArrayList$ArrayListIterator.next(ArrayList.java)
// for(Observer observer : observers)
for( Iterator< Observer > it = observers.iterator(); it.hasNext() ; )
{
Observer observer = it.next();
observer.notifyUploadCompleteted(isSucccess);
}
}
现在我上次在notifyObserverNewRemoteBackup 方法的Observer observer = it.next(); 行上得到了excption
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)
---------- 编辑 --------- ----------
我遵循了 Anubian Noob 的建议,并实施了一个同步列表,但我仍然遇到异常。
这是我更新的代码:
// Singleton
public synchronized static ObserverSubjectManager getInstance()
{
if(instance == null)
{
instance = new ObserverSubjectManager();
return instance;
}
return instance;
}
private ObserverSubjectManager()
{
// observers = new ArrayList<>();
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);
}
}
}
堆栈跟踪:
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)
【问题讨论】:
-
我的猜测是另一个线程可能正在注册/注销观察者,这会触发
ConcurrentModificationException。您是否在日志中看到任何关于观察者在ConcurrentModificationException之前注册/取消注册的信息? -
就我个人而言,我会说您在迭代期间迭代和更改数组列表的内容。虽然我看不出你现在给出的代码量在哪里
-
对于初学者,只需使用增强的
for循环。这不是您的问题,但您的代码由于手动执行而更难阅读。 -
@chrylis 我正在使用增强的
for循环,正如您在 cmets 中看到的那样,但从我在互联网上阅读的内容来看,因此建议使用迭代器并使用迭代器来访问和修改列表