Volley 图片加载器 ConcurrentModificationException

3

我在我的项目中使用Volley图像加载器从服务器上加载图像。但在某些情况下,我会遇到以下错误并导致应用程序崩溃。

            java.util.ConcurrentModificationException
          at java.util.LinkedList$LinkIterator.next(LinkedList.java:124)
          at com.android.volley.toolbox.ImageLoader$4.run(ImageLoader.java:440)
          at android.os.Handler.handleCallback(Handler.java:739)
          at android.os.Handler.dispatchMessage(Handler.java:95)
          at android.os.Looper.loop(Looper.java:135)
          at android.app.ActivityThread.main(ActivityThread.java:5343)
          at java.lang.reflect.Method.invoke(Native Method)
          at java.lang.reflect.Method.invoke(Method.java:372)
          at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
          at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)

我找不到这个错误的原因和解决方法,请帮帮我。

Global.java

import android.app.Application;
import android.text.TextUtils;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.Volley;
import com.example.volley.LruBitmapCache;
import java.util.HashMap;
public class Global extends Application{
    public static final String TAG = Global.class.getSimpleName();
    private RequestQueue mRequestQueue;
    private ImageLoader mImageLoader;
    private static Global mInstance;
    @Override
    public void onCreate() {
        super.onCreate();
        mInstance = this;
    }
    public static synchronized Global getInstance() {
        return mInstance;
    }
    public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            mRequestQueue = Volley.newRequestQueue(getApplicationContext());
        }
        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) {
        req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
        getRequestQueue().add(req);
    }
    public void cancelPendingRequests(Object tag) {
        if (mRequestQueue != null) {
            mRequestQueue.cancelAll(tag);
        }
    }
}

LruBitmapCache.java

import com.android.volley.toolbox.ImageLoader.ImageCache;
import android.graphics.Bitmap;
import android.support.v4.util.LruCache;

public class LruBitmapCache extends LruCache<String, Bitmap> implements ImageCache {
    public static int getDefaultLruCacheSize() {
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
        final int cacheSize = maxMemory / 8;

        return cacheSize;
    }

    public LruBitmapCache() {
        this(getDefaultLruCacheSize());
    }

    public LruBitmapCache(int sizeInKiloBytes) {
        super(sizeInKiloBytes);
    }

    @Override
    protected int sizeOf(String key, Bitmap value) {
        return value.getRowBytes() * value.getHeight() / 1024;
    }

    @Override
    public Bitmap getBitmap(String url) {
        return get(url);
    }

    @Override
    public void putBitmap(String url, Bitmap bitmap) {
        put(url, bitmap);
    }
}

将图像加载到网络视图的代码

ImageLoader myLoader = Global.getInstance().getImageLoader();
networkImageView.setImageUrl(thumbnailURL, myLoader);
myLoader.get(thumbnailURL, new ImageLoader.ImageListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
        //Set Error image
    }
    @Override
    public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) {
        if (response.getBitmap() != null) {
            //Set BitMap
        }
        else{
            //Set Loading image
        }
    }
});

我的Costume网络视图图像视图监听器

public class NetworkImageViewListener {

    private final String TAG_THUMBNAIL_ERROR = "THUMBNAIL_ERROR";
    private final String TAG_THUMBNAIL_RECEIVED = "THUMBNAIL_RECEIVED";

    private String TAG = getClass().getSimpleName();


    private boolean original_image_loaded = false;
    public void loadImage(final Context context,final String url,final NetworkImageView networkImageView, final int approx_width, final int approx_height,final boolean thumbnail, final ProgressBar progressBar, final boolean is_Store){
        networkImageView.setAdjustViewBounds(true);
        final int picture_not_found = R.drawable.ic_profile_picture_not_found;
        final int picture_not_loaded = R.drawable.ic_profile_picture_not_loaded;

        if (url != null && !url.equals("null")&& !url.equals("NULL")&& !url.equals("")) {
            final String originalURL = getImageUrl(url, approx_width, approx_height);

            final Bitmap cacheImage = getCacheImage(context, originalURL);
            if (cacheImage==null) {

                if(progressBar!=null){
                    progressBar.setVisibility(View.VISIBLE);
                }
                if (thumbnail) {
                    final String thumbnailURL = getImageThumbnailUrl(url, approx_width, approx_height);

                    ImageLoader thumbnailLoader = Global.getInstance().getImageLoader();
                    networkImageView.setImageUrl(thumbnailURL, thumbnailLoader);
                    thumbnailLoader.get(thumbnailURL, new ImageLoader.ImageListener() {
                        @Override
                        public void onErrorResponse(VolleyError error) {
                            if(progressBar==null){
                                networkImageView.setImageResource(picture_not_found);
                            }
                            networkImageView.setTag(TAG_THUMBNAIL_ERROR);
                            load_Original(context, originalURL, networkImageView, progressBar, is_Store, picture_not_loaded);
                        }
                        @Override
                        public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) {
                            if (response.getBitmap() != null) {
                                networkImageView.setImageBitmap(response.getBitmap());
                                networkImageView.setTag(TAG_THUMBNAIL_RECEIVED);
                                load_Original(context, originalURL, networkImageView, progressBar, is_Store, picture_not_loaded);
                            } else if (progressBar==null) {
                                networkImageView.setImageResource(picture_not_found);
                            }
                        }
                    });
                }
                else{
                    load_Original(context,originalURL,networkImageView,progressBar,is_Store,picture_not_loaded);
                }
            } else {
                networkImageView.setImageBitmap(cacheImage);
            }
        } else {
            networkImageView.setImageResource(picture_not_found);
        }
    }
    private void load_Original(final Context context,final String originalURL,final NetworkImageView networkImageView, final ProgressBar progressBar, final boolean is_Store,final int picture_not_loaded){
        final Drawable temp = networkImageView.getDrawable();
        final String imageviewTag = (String) networkImageView.getTag();
        ImageLoader imageLoader = Global.getInstance().getImageLoader();
        networkImageView.setImageUrl(originalURL, imageLoader);
        imageLoader.get(originalURL, new ImageLoader.ImageListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                if (progressBar != null) {
                    progressBar.setVisibility(View.GONE);
                }
                if (temp != null && imageviewTag != null && !imageviewTag.equals(TAG_THUMBNAIL_ERROR)) {
                    networkImageView.setImageDrawable(temp);
                } else if (temp != null && imageviewTag != null && imageviewTag.equals(TAG_THUMBNAIL_RECEIVED)) {
                    networkImageView.setImageDrawable(temp);
                } else {
                    networkImageView.setImageResource(picture_not_loaded);
                }
            }

            @Override
            public void onResponse(ImageLoader.ImageContainer response, boolean shouldAnimate) {
                if (response.getBitmap() != null) {
                    if (progressBar != null) {
                        progressBar.setVisibility(View.GONE);
                    }
                    networkImageView.setImageBitmap(response.getBitmap());
                    if (is_Store) {
                        setCacheImage(context, originalURL, response.getBitmap());
                    }
                } else {
                    networkImageView.setImageDrawable(temp);
                }
            }
        });
    }

    private static String getImageUrl(String url, int aprox_width, int aprox_height){
        int index = url.lastIndexOf('/');
        String path = url.substring(0, index);
        String file_name =  url.substring(index + 1);
        String result = path+"/"+aprox_width+"/"+aprox_height+"/"+file_name;
        return result;
    }

    private static String getImageThumbnailUrl(String url, int approx_width, int aprox_height){
        int index = url.lastIndexOf('/');
        String path = url.substring(0, index);
        String file_name =  url.substring(index + 1);
        String result = path+"/"+approx_width+"/"+aprox_height+"/tbnil"+"/"+file_name;
        return result;
    }

    private String profile_picture_folder_name = "PP";
    private void setCacheImage(Context context, String url, Bitmap bitmap){
        try {
            if (!getCacheDirectory(context).equals("")) {
                String filename = getFileName(url);
                File folder = new File(getCacheDirectory(context)+"/"+profile_picture_folder_name+"/");
                if (!folder.exists()) {
                    folder.mkdir();
                }
                if (folder.exists()) {
                    File dest = new File(folder, filename);
                    FileOutputStream out = new FileOutputStream(dest);
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 40, out);
                    out.flush();
                    out.close();
                }
            }
        } catch (Exception e) {
            Log.developer(TAG,e.getMessage());
        }
    }
    private Bitmap getCacheImage(Context context,String url){
        try {
            if (!getCacheDirectory(context).equals("")) {
                String filename = getFileName(url);
                File folder = new File(getCacheDirectory(context)+"/"+profile_picture_folder_name+"/");
                if (folder.exists()) {
                    FileInputStream fis = null;
                    File imageFile = new File(folder, filename);
                    if (imageFile.exists()) {
                        fis = new FileInputStream(imageFile);
                        return BitmapFactory.decodeStream(fis);
                    }
                }
            }
        } catch (FileNotFoundException e) {
            Log.developer(TAG, e.getMessage());
        }
        return null;
    }
    private String getCacheDirectory(Context context){
        String cachePath="";
        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) || !Environment.isExternalStorageRemovable()) {
            if (context.getExternalCacheDir() != null && context.getExternalCacheDir().exists()) {
                cachePath = context.getExternalCacheDir().getPath(); // most likely your null value
            }
            else if (context.getCacheDir() != null && context.getCacheDir().exists()) {
                cachePath = context.getCacheDir().getPath();
            }
        } else {
            if (context.getCacheDir() != null && context.getCacheDir().exists()) {
                cachePath = context.getCacheDir().getPath();
            }
        }
        return cachePath;
    }

    public String getFileName(String urlStr) {
        return urlStr.substring(urlStr.lastIndexOf('/') + 1, urlStr.length());
    }
}

1
请发布完整的堆栈跟踪和与之相关的代码。 - Yazan
@Yazan:我已经按照你说的添加了。 - Vinil Chandran
我认为从扩展Application的类中创建实例不是一个好主意,对吧?这可能会有关系吗? - Yazan
@Yazan,如果您能,请编辑一下,或者给出一个示例,好让它变得正确?我不明白您的意思。 - Vinil Chandran
再想一想,我认为这不是问题,因为您正在使用mInstance=this;而不是创建Global的新实例。 - Yazan
显示剩余2条评论
1个回答

0
你需要实现两个ImageLoader,一个用于缩略图,另一个用于全尺寸图片。 按照以下方式修改你的RequestQueue单例:
//..
private ImageLoader mImageLoader;
private ImageLoader mThumbLoader;
//...
// Then in constructor
mThumbLoader = new ImageLoader(mRequestQueue, new ImageLoader.ImageCache() { ... });
mImageLoader = new ImageLoader(mRequestQueue, new ImageLoader.ImageCache() { ... });

// And then you build two getters
protected ImageLoader getImageLoader() {
    return mImageLoader;
}

protected ImageLoader getThumbLoader() {
    return mThumbLoader;
}

如果您调用mThumbLoader来获取缩略图,调用mImageLoader来获取全尺寸图像,它将正常工作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接