1

I used this tutorial to show and cache image in grid using Volley. when internet is connected , it works fine .but after disconnecting the image do not show.it seems Volley do not cache any image. the problem is, there is no complete documentation about caching image using Volley.here is my code :

xml:

<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:id="@+id/container_toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <include
            android:id="@+id/toolbar"
            layout="@layout/toolbar" />
    </LinearLayout>


    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#F4F4F6"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context=".Content_Gallery_Activity">

        <TextView
            android:id="@+id/text_gallery_title"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true"
            android:gravity="center"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:textAppearance="?android:attr/textAppearanceSmall" />

        <RelativeLayout
            android:id="@+id/relative_gallery"
            android:layout_width="match_parent"
            android:layout_height="80dp"
            android:layout_below="@+id/text_gallery_title"
            android:layout_marginLeft="8dp"
            android:layout_marginRight="8dp"
            android:layout_marginTop="10dp"
            android:background="@drawable/rect_lst_tree"
            android:paddingLeft="10dp"
            android:paddingRight="10dp" >

            <com.beardedhen.androidbootstrap.AwesomeTextView
                android:id="@+id/font_time"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_toLeftOf="@+id/tv_date_gallery"
                app:bootstrapBrand="info"
                app:fontAwesomeIcon="fa_clock_o"
                >
            </com.beardedhen.androidbootstrap.AwesomeTextView>

            <TextView
                android:id="@+id/tv_date_gallery"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:layout_marginLeft="5dp"
                android:textAppearance="?android:attr/textAppearanceSmall"
                android:textColor="#1B131B"
                android:textSize="13dp" >
            </TextView>

            <TextView
                android:id="@+id/text_image_count"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="10dp"
                android:layout_toRightOf="@+id/gallery_thumb"
                android:text="Small"
                android:textAppearance="?android:attr/textAppearanceSmall"
                android:textColor="#F01435"
                android:textSize="12dp" />

            <ir.whc.news.views.CircularNetworkImageView
                android:id="@+id/gallery_thumb"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_centerVertical="true"
                >
            </ir.whc.news.views.CircularNetworkImageView>
        </RelativeLayout>

        <GridView
            android:id="@+id/gridView1"
            android:layout_width="match_parent"
            android:layout_height="fill_parent"
            android:layout_below="@+id/relative_gallery"
            android:columnWidth="100dp"
            android:horizontalSpacing="1dp"
            android:numColumns="auto_fit"
            android:paddingTop="10dp"
            android:stretchMode="spacingWidthUniform"
            android:verticalSpacing="8dp" >
        </GridView>

    </RelativeLayout>
</LinearLayout>


<fragment
    android:id="@+id/fragment_navigation_drawer"
    android:name="ir.whc.news.activity.FragmentDrawer"
    android:layout_width="@dimen/nav_drawer_width"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    app:layout="@layout/fragment_navigation_drawer"
    tools:layout="@layout/fragment_navigation_drawer" />

Actitvity:

    grd.setAdapter(new MyImageAdapter(galleryItem.get_images()));
        grd.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Intent intent = new Intent(ContentGalleryActivity.this, DisplayImageActivity.class);
                intent.putExtra("largimage_url", galleryItem.get_images().get(position).get_largimage_path());
                startActivity(intent);
            }
        });

adapter:

    class MyImageAdapter extends BaseAdapter {

        ArrayList<ImageItem> imageItems;

        public MyImageAdapter(ArrayList<ImageItem> imageItems)
        {
            this.imageItems=imageItems;
        }

        @Override
        public int getCount() {
            return imageItems.size();
        }

        @Override
        public Object getItem(int position) {
            return imageItems.get(position);
        }

        @Override
        public long getItemId(int position) {
            return imageItems.get(position).get_id();
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

            View view = convertView;
            final ViewHolder gridViewImageHolder;
//            check to see if we have a view
            if (view == null) {
                view = getLayoutInflater().inflate(R.layout.grid_image_item, parent, false);
                gridViewImageHolder = new ViewHolder();
                gridViewImageHolder.imageView = (ImageView) view.findViewById(R.id.image_grid_networkImageView);
                view.setTag(gridViewImageHolder);
            } else {
                gridViewImageHolder = (ViewHolder) view.getTag();
            }

            mNetworkImageView = (NetworkImageView) gridViewImageHolder.imageView;
            mNetworkImageView.setDefaultImageResId(R.drawable.ic_launcher);
            mNetworkImageView.setErrorImageResId(android.R.drawable.ic_dialog_alert);
            mNetworkImageView.setAdjustViewBounds(true);
            mNetworkImageView.setImageUrl(imageItems.get(position).get_thumb_path(), imageLoader);

            return view;
        }
    }

Imageloder:

imageLoader = MyApplication.getInstance().getImageLoader();
        imageLoader.get(galleryItem.get_imgPath(), imageLoader.getImageListener(img_thumb,
                R.drawable.ic_launcher,
                android.R.drawable.ic_dialog_alert));
        img_thumb.setImageUrl(galleryItem.get_imgPath(), imageLoader);

LruBitmapCache:

import android.graphics.Bitmap;
import android.support.v4.util.LruCache;

import com.android.volley.toolbox.ImageLoader.ImageCache;

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);
    }
}

what's wrong with my code.I'm tired of struggling.

MSepehr
  • 890
  • 2
  • 13
  • 36

2 Answers2

3

what seems to be the issue is that your images does not have cache headers that tells Volley to cache it. You can explicitly force the cache by extending your ImageLoader which you initialize in MyApplication.

for example:

mImageLoader = new ImageLoader(this.mRequestQueue,
                new LruBitmapCache()) {
@Override
    protected Request<Bitmap> makeImageRequest(String requestUrl, int maxWidth, int maxHeight,
                ScaleType scaleType, final String cacheKey) {
            return new ImageRequest(requestUrl, new Listener<Bitmap>() {
                @Override
                public void onResponse(Bitmap response) {
                    onGetImageSuccess(cacheKey, response);
                }
            }, maxWidth, maxHeight, scaleType, Config.RGB_565, new ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    onGetImageError(cacheKey, error);
                }
            }){
      @Override
                public Response<Bitmap> parseNetworkResponse(NetworkResponse response) {
                    Response<Bitmap> resp = super.parseNetworkResponse(response);
                    if(!resp.isSuccess()) {
                        return resp;
                    }
                    long now = System.currentTimeMillis();
                    Cache.Entry entry = resp.cacheEntry;
    if(entry == null) {

        entry = new Cache.Entry();
        entry.data = response.data;
        entry.softTtl = now + 1 * 60 * 60 * 1000; // keeps valid(no refresh) for 1hr
        entry.responseHeaders = response.headers;
    }
    entry.ttl = now + 30l * 24 * 60 * 60 * 1000;  //keeps cache for 30 days
                    return Response.success(resp.result, entry);
                }

    };
        }
};

This way your images will be cached in the disk for 30 days but also refresh when needed.

similar issue here

Community
  • 1
  • 1
kalin
  • 3,546
  • 2
  • 25
  • 31
0

Here is what djodjo's answer looks like in Kotlin.

val imageLoader: ImageLoader
    get() {
        requestQueue
        if (mImageLoader == null) {
            mImageLoader = object : ImageLoader(
                this.mRequestQueue,
                LruBitmapCache()
            ) {
                override fun makeImageRequest(
                    requestUrl: String?, maxWidth: Int,
                    maxHeight: Int, scaleType: ImageView.ScaleType?, cacheKey: String?
                ): Request<Bitmap> {
                    return object : ImageRequest(requestUrl,
                        Response.Listener<Bitmap>
                        { response -> onGetImageSuccess(cacheKey, response) },
                        maxWidth,
                        maxHeight,
                        scaleType,
                        Bitmap.Config.RGB_565,
                        Response.ErrorListener {
                            onGetImageError(cacheKey, it)
                        }
                    ) {
                        override fun parseNetworkResponse(response: NetworkResponse?): Response<Bitmap> {
                            val resp = super.parseNetworkResponse(response)
                            if (!resp.isSuccess()) {
                                return resp;
                            }
                            val now = System.currentTimeMillis();
                            var entry = resp.cacheEntry;
                            if (entry == null) {

                                entry = Cache.Entry();
                                entry.data = response?.data;
                                entry.softTtl =
                                    now + 1 * 60 * 60 * 1000; // keeps valid(no refresh) for 1hr
                                entry.responseHeaders = response?.headers;
                            }
                            entry.ttl =
                                now + 30L * 24 * 60 * 60 * 1000;  //keeps cache for 30 days
                            return Response.success(resp.result, entry);
                        }
                    }


                }
            }
        }
        return this.mImageLoader!!
    }

Here is LruBitmapCache class in Kotlin

import android.graphics.Bitmap
import android.util.LruCache
import com.android.volley.toolbox.ImageLoader
class LruBitmapCache @JvmOverloads constructor(sizeInKiloBytes: Int 
defaultLruCacheSize):LruCache<String?, Bitmap>(sizeInKiloBytes),
ImageLoader.ImageCache {
override fun sizeOf(key: String?, value: Bitmap): Int {
    return value.rowBytes * value.height / 1024
}

override fun getBitmap(url: String): Bitmap {
    return get(url)
}

override fun putBitmap(url: String, bitmap: Bitmap) {
    put(url, bitmap)
}

companion object {
    val defaultLruCacheSize: Int
        get() {
            val maxMemory = (Runtime.getRuntime().maxMemory() / 1024).toInt()
            return maxMemory / 8
        }
}
}

Hope it might help someone

MRamzan
  • 161
  • 2
  • 7