如何正确设置Volley以从URL下载图片

5

我知道Volley应该使下载和缓存图像变得无忧无虑,但我已经努力了几个小时才能正确地实现它。我在网上搜索了许多与volley相关的文章,包括stackoverflow上的许多文章,但我找到的例子似乎都不适用于我。

我只想使用volley从给定的URL下载和缓存图像,而不是进行任何HTTP JSON REST处理。只需获取给定的URL,下载位图并将其设置为imageview,然后将其添加到缓存中。

这是我迄今为止的最新尝试。如何正确地使用volley加载和缓存图像?

if (data.getImageUrl() != null) {
        try {

            holder.thumbnail.setTag(data.getImageUrl());

        Cache cache = ImgController.getInstance().getRequestQueue().getCache();
        Cache.Entry entry = cache.get(data.getImageUrl());

            if (entry != null) {
                try {
                    String cImg = new String(entry.data, "UTF-8");
                    LruBitmapCache bitmapCache = new LruBitmapCache();
                    holder.thumbnail.setImageBitmap(bitmapCache.getBitmap(cImg));
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }

            } else {

                ImageLoader imageLoader = ImgController.getInstance().getImageLoader();

                imageLoader.get(data.getImageUrl(), new ImageListener() {

                    @Override
                    public void onErrorResponse(VolleyError error) {

                        holder.thumbnail.setImageResource(R.drawable.filler_icon);

                    }

                    @Override
                    public void onResponse(ImageLoader.ImageContainer response, boolean arg1) {
                        if (response.getBitmap() != null) {
                            // load image into imageview
                            holder.thumbnail.setImageBitmap(response.getBitmap());

                        }
                    }
                });
            }

            return convertView;
        } catch (Exception e) {
            e.printStackTrace();
            Log.v(DEBUG_TAG, "no image: ", e);
            holder.thumbnail.setImageResource(R.drawable.filler_icon);


        }
    }else {
        return null;
    }


    return convertView;
}

当我运行这个程序时,出现了一个指向这一行的空指针异常。
Cache cache = ImgController.getInstance().getRequestQueue().getCache();

我已经设置了以下单例类来处理请求。
public class ImgController extends Application {

public static final String TAG = ImgController.class.getSimpleName();
private RequestQueue requestQueue;
private ImageLoader imageLoader;

private static ImgController instance;

@Override
public void onCreate() {
    super.onCreate();
    instance = this;

}
public static synchronized ImgController getInstance(){
    return instance;
}
public RequestQueue getRequestQueue(){
    if(requestQueue == null){
        requestQueue = Volley.newRequestQueue(getApplicationContext());
    }
    return this.requestQueue;
}
public ImageLoader getImageLoader(){
    getRequestQueue();
    if(imageLoader ==  null){
        imageLoader = new ImageLoader(this.requestQueue, new LruBitmapCache());
        }

    return this.imageLoader;
}
public <T> void addToRequestQueue(Request<T> req, String tag) {
    // set the default tag if tag is empty
    req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
    getRequestQueue().add(req);
}

public <T> void addToRequestQueue(Request<T> req) {
    req.setTag(TAG);
    getRequestQueue().add(req);
}

public void cancelPendingRequests(Object tag) {
    if (requestQueue != null) {
        requestQueue.cancelAll(tag);
    }
}

以及以下的LruBitmapCache类

public class LruBitmapCache extends LruCache<String, Bitmap> implements ImageLoader.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 maxSize) {
    super(maxSize);
}

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

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

}


请检查您的SD卡是否生成了任何缓存图像文件夹。如果是,请检查它是否有图像或为空白/空的?如果为空白,则意味着它没有从给定的URL获取图像,否则您需要检查从SD卡文件夹检索缓存图像的代码。 - VVB
5个回答

11

(抱歉我的英语水平不好^^;)

Volley旨在使下载和缓存图像变得非常简单

是的!Volley非常简单。您无需考虑缓存命中,图像加载等等...

只需要使用NetworkImageView。以下是示例。

layout_example.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">

    <com.android.volley.toolbox.NetworkImageView
            android:id="@+id/photo"
            android:adjustViewBounds="true"
            android:scaleType="fitCenter"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

</RelativeLayout>

MainActivity.java

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.layout_example);
    NetworkImageView nv = (NetworkImageView) findViewById(R.id.photo);
    nv.setDefaultImageResId(R.drawable.default_image); // image for loading...
    nv.setImageUrl(imageUrl, ImgController.getInstance().getImageLoader()); //ImgController from your code.
}

NetworkImageView自动从后台队列加载图像,并在此视图被取消附加时使用ImageLoader取消请求。而ImageLoader 自动使用内存Lru缓存和磁盘缓存。 NetworkImageView是最佳解决方案。

其他信息

NetworkImageView
       |
  ImageLoader (uses `LruBitmapCache` you implemented.)
       |
 RequestQueue (uses `DiskBasedCache`. it is already implemented in volley.)

问题是当我尝试获取一个imageLoader对象时,由于某种原因它总是返回null。 - feilong
1
你在 AndroidManifest.xml 文件中注册了自定义应用程序上下文吗? - Cinakyn
like this.<application android:name="ImgController" android:allowBackup="true" android:icon="@drawable/icon" android:label="@string/app_name"> - Cinakyn
将android:name="ImgController"添加到我的清单文件中会导致Gradle抛出以下错误INSTALL_PARSE_FAILED_MANIFEST_MALFORMED。我之前已经添加了其他所有内容。 - feilong
如果您没有注册自定义应用程序(ImgController),则不会调用imgController的“onCreate()”方法,并且“getInstance()”将始终返回null。请检查您的清单文件语法。请上传您的清单文件。 - Cinakyn
嘿,你是对的!我必须将ImgController重构到不同的包中,才能使它在清单中正常工作。谢谢Cinakyn,我非常感激你的耐心。 - feilong

10
Volley提供了一个用于图像请求的回调函数,您可以使用以下代码:

以下是示例代码:

    ImageView iv = null; /*Attach the Pointer for ImageView*/
    RequestQueue requestAdministrator = null; /*Attach the Pointer for Volley*/

    ImageRequest ir = new ImageRequest(url, new Response.Listener<Bitmap>() {
        @Override
        public void onResponse(Bitmap response) {
            // callback
            iv.setImageBitmap(response);
        }
    }, 100, 100, null, null);
    // 100 is your custom Size before Downloading the Image.
    requestAdministrator.add(ir);

1

我有一个更简单的解决方案,可以从URL显示图像并将其存储在缓存中,而不需要添加额外的类,只用MainActivity就可以实现。 这可能会对某些人有所帮助...

这是我的XML代码,仅显示ImageView:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.natalie.volley.MainActivity">


    <ImageView
        android:id="@+id/ivImageView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="50dp"/>

</android.support.constraint.ConstraintLayout>

这是我的MainAvtivity.java文件:

  import android.graphics.Bitmap;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.widget.ImageView;

    import com.android.volley.RequestQueue;
    import com.android.volley.Response;
    import com.android.volley.VolleyError;
    import com.android.volley.toolbox.ImageRequest;
    import com.android.volley.toolbox.Volley;

    public class MainActivity extends AppCompatActivity {

        private String url = "http://kingofwallpapers.com/picture/picture-010.jpg";
        ImageView ivImageView;
        RequestQueue mRequestQueue;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            ivImageView = (ImageView)findViewById(R.id.ivImageView);
            mRequestQueue = Volley.newRequestQueue(this.getApplicationContext());
            ImageRequest imageRequest = new ImageRequest(url, new BitmapListener(), 0, 0, null, null, new MyErrorListener());

            mRequestQueue.add(imageRequest);
        }

        private class BitmapListener implements Response.Listener<Bitmap> {
            @Override
            public void onResponse(Bitmap response) {
// response = your url's bitmap
                ivImageView.setImageBitmap(response);

            }
        }

        private class MyErrorListener implements Response.ErrorListener {
            @Override
            public void onErrorResponse(VolleyError error) {
//store a default image if connection failed
                ivImageView.setImageResource(R.drawable.error_icon);
            }
        }
    }

不要忘记在Manifest.xml中添加<uses-permission android:name="android.permission.INTERNET" />,以及在build.gradle的依赖中添加compile 'com.android.volley:volley:1.0.0'

0

ImageRequest已被弃用,因此我现在按照以下方式进行:

步骤1:首先按照以下方式创建Application

public class YourApplicationClass extends Application {
    private static YourApplicationClass sInstance;
    private RequestQueue mRequestQueue;
    private ImageLoader mImageLoader;

    public static YourApplicationClass getInstance(){
        return sInstance;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        sInstance = this;

        mRequestQueue = Volley.newRequestQueue(this);
        mImageLoader = new ImageLoader(this.mRequestQueue, new ImageLoader.ImageCache() {

            private final LruCache<String, Bitmap> mCache = new LruCache<String, Bitmap>(10);

            public Bitmap getBitmap(String url) {
                return mCache.get(url);
            }

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

        });
    }

    public RequestQueue getRequestQueue(){
        return mRequestQueue;
    }

    public ImageLoader getImageLoader(){
        return mImageLoader;
    }
}

第二步:现在从任何活动(activity)片段(fragment)中按以下方式进行图像请求

YourApplicationClass.getInstance().getImageLoader().get(image_url, new ImageLoader.ImageListener() {
                @Override
                public void onResponse(ImageLoader.ImageContainer imageContainer, boolean b) {
                 Bitmap bitmap = imageContainer.getBitmap();
                 //use bitmap 
                }

                @Override
                public void onErrorResponse(VolleyError volleyError) {

                }
            });

我认为ImageRequest并没有被弃用,但是你正在使用的构造函数已经被弃用了。请使用https://github.com/mcxiaoke/android-volley/blob/9aba4f5f861ab547751aa572c8559467dfa59270/src/main/java/com/android/volley/toolbox/ImageRequest.java#L72代替https://github.com/mcxiaoke/android-volley/blob/9aba4f5f861ab547751aa572c8559467dfa59270/src/main/java/com/android/volley/toolbox/ImageRequest.java#L89。 - SAYE

0

已被删除。 - Michele Dorigatti

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