我在崩溃报告中收到以下错误,我在确定它来自何处或如何解决时遇到了一些麻烦。
我感到困惑的原因 - 崩溃似乎引用了Volley库它自己,而不是我实际编写的任何代码(崩溃中的任何内容似乎都指向任何我的代码)。
有谁知道如何或者我可以做些什么来解决这次崩溃?
非常感谢任何建议。
Fatal Exception: java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:787)
at java.util.HashMap$ValueIterator.next(HashMap.java:819)
at com.android.volley.toolbox.ImageLoader$4.run(ImageLoader.java:464)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5527)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
public class VolleyManager {
private static final String TAG = VolleyManager.class.getSimpleName();
/** Number of network request dispatcher threads to start. */
private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
private static VolleyManager mInstance;
private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;
private static Context mContext;
private VolleyManager(Context context) {
mContext = context.getApplicationContext();
mRequestQueue = getRequestQueue();
}
public static synchronized VolleyManager getInstance(Context context) {
if (mInstance == null) {
mInstance = new VolleyManager(context);
}
return mInstance;
}
@SuppressWarnings("deprecation")
public RequestQueue getRequestQueue() {
if (mRequestQueue == null) {
File cacheDir = new File(FMCacheManager.getCacheBaseDir(mContext));
String userAgent = "volley/0";
try {
String packageName = mContext.getPackageName();
PackageInfo info = mContext.getPackageManager().getPackageInfo(packageName, 0);
userAgent = packageName + "/" + info.versionCode;
} catch (NameNotFoundException ignore) {
}
HttpStack stack = new HurlStack();
Network network = new BasicNetwork(stack);
HandlerThread mHandlerThread = new HandlerThread(TAG, android.os.Process.THREAD_PRIORITY_BACKGROUND);
mHandlerThread.start();
ResponseDelivery delivery = new ExecutorDelivery(new Handler(mHandlerThread.getLooper()));
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network, DEFAULT_NETWORK_THREAD_POOL_SIZE, delivery);
queue.start();
mRequestQueue = queue;
}
return mRequestQueue;
}
public ImageLoader getImageLoader() {
getRequestQueue();
if (mImageLoader == null) {
mImageLoader = new ImageLoader(this.mRequestQueue,
new LruBitmapCache());
}
return this.mImageLoader;
}
public <T> void addToRequestQueue(Request<T> req, String tag) {
if (req != null) {
Log.d(TAG, "request: " + req.getUrl());
// set the default tag if tag is empty
req.setTag(FMUtils.isNullOrEmpty(tag) ? TAG : tag);
getRequestQueue().add(req);
}
}
public void cancelPendingRequests(Object tag) {
if (mRequestQueue != null) {
mRequestQueue.cancelAll(tag);
}
}
}
答案 0 :(得分:0)
是的,堆栈跟踪表明崩溃发生在ImageLoader
的{{1}}方法中,并且与迭代run()
有关。
您可以看到(某些版本)HashMap
in here。每个循环都有这个:
ImageLoader.java
现在,如果另一个线程在迭代时修改for (BatchedImageRequest bir : mBatchedResponses.values()) {
for (ImageContainer container : bir.mContainers) {
// If one of the callers in the batched request canceled the request
// after the response was received but before it was delivered,
// skip them.
if (container.mListener == null) {
continue;
}
if (bir.getError() == null) {
container.mBitmap = bir.mResponseBitmap;
container.mListener.onResponse(container, false);
} else {
container.mListener.onErrorResponse(bir.getError());
}
}
}
或mBatchedResponses.values()
,则会发生bir.mContainers
。它们不是“线程安全”的集合。
有this other recent discussion指出单独的ConcurrentModificationException
个实例应该用于任何同步(并行)图像加载操作。 Fernando Jascovich写道:
你必须实现两个ImageLoader,一个用于缩略图和 另一个用于全分辨率图像。
因此,您可以检查是否在自己的代码中启动任何并行图像下载操作,查看其他讨论并遵循建议的方法。
关于“如何诊断ConcurrentModificationException”的更通用的答案:请参阅堆栈跟踪,查看确切的代码文件名和行号。如果它在for-each循环中迭代一个集合,你可能同时在另一个线程中修改集合。这可能只是偶尔发生,并且很长时间没有被注意到。当修改所述for-each循环内的集合时也会发生相同的异常,如例如所解释的那样。 in this discussion