How to get Volley NetworkImageView to work offline

I use Volley NetworkImageView to download images from the Internet and impressions in my listview . Now I want the Volley NetworkImageView show saved images when there is no network available. Volley already cached URL images as a key, because when I use

 Entry entry = SingletonRequestQueue.getInstance(context).getRequestQueue().getCache().get(imageURL); 

entry.data not null. But my problem is that the image resolutions are high and I can’t use

 Bitmap b = BitmapFactory.decodeByteArray(entry.data, 0, entry.data.length); 

because it creates a lot of delays, and I have to reinvent the wheel, because again I have to create asynctask to see when the listview scrolls, to cancel the decoding, processing the bitmap , creating in the memory cache, finding the best example value and ...

so better. The idea is to just do some of the tricks that Volley NetworkImageView uses to use their own DiskLRUCache to show them when there is no network.

Any idea?

My code is:

 public class SingletonRequestQueue { private static SingletonRequestQueue mInstance; private RequestQueue mRequestQueue; private ImageLoader mImageLoader; private static Context mCtx; private LruBitmapCache mLruBitmapCache; private SingletonRequestQueue(Context context) { mCtx = context; mRequestQueue = getRequestQueue(); mLruBitmapCache = new LruBitmapCache(LruBitmapCache.getCacheSize(context)); mImageLoader = new ImageLoader(mRequestQueue,mLruBitmapCache); } public static synchronized SingletonRequestQueue getInstance(Context context) { if (mInstance == null) { mInstance = new SingletonRequestQueue(context); } return mInstance; } public RequestQueue getRequestQueue() { if (mRequestQueue == null) { // getApplicationContext() is key, it keeps you from leaking the // Activity or BroadcastReceiver if someone passes one in. mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext(),new OkHttpStack()); // mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext()); } return mRequestQueue; } public <T> void addToRequestQueue(Request<T> req) { getRequestQueue().add(req); } public ImageLoader getImageLoader() { return mImageLoader; } public LruBitmapCache getLruBitmapCache() { return mLruBitmapCache; } public void setLruBitmapCache(LruBitmapCache lruBitmapCache) { mLruBitmapCache = lruBitmapCache; } } 

and in my adapter:

 public IssueListAdapter(Context context, int resource, List<Issue> objects) { super(context, resource, objects); this.context = context; this.mIssueList = objects; mImageLoader = SingletonRequestQueue.getInstance(context).getImageLoader(); } public static class ViewHolder{ public NetworkImageView mNetworkImageView; public TextView mFee; public TextView mName; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if(convertView == null){ holder = new ViewHolder(); LayoutInflater inflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.gridview_issuelist_item, parent, false); holder.mNetworkImageView = (NetworkImageView)convertView.findViewById(R.id.NetworkImageView_MainActivity_issue_image); holder.mName = (TextView)convertView.findViewById(R.id.TextView_MainActivity_name); holder.mFee = (TextView)convertView.findViewById(R.id.TextView_MainActivity_fee); Utility.settingTypfaceFont(context, holder.mName); Utility.settingTypfaceFont(context, holder.mFee); convertView.setTag(holder); }else{ holder = (ViewHolder)(convertView.getTag()); } final Issue issue = mIssueList.get(position); holder.mName.setText(issue.getTitle()); holder.mFee.setText(String.valueOf(issue.getFee())); String imageURL = issue.getPublicCover(); holder.mNetworkImageView.setImageUrl(imageURL, mImageLoader); holder.mNetworkImageView.setDefaultImageResId(R.drawable.placeholder2);; /* Entry entry = SingletonRequestQueue.getInstance(context).getRequestQueue().getCache().get(imageURL); if(entry != null && entry.data != null){ byte[] imageByte = entry.data; loadBitmap(imageByte, holder.mNetworkImageView,imageURL); }else{ holder.mNetworkImageView.setImageUrl(imageURL, mImageLoader); }*/ return convertView; } @Override public int getCount() { if(mIssueList != null){ return mIssueList.size(); } else{ return 0; } } public List<Issue> getIssueList() { return mIssueList; } } 
+4
source share
6 answers

Just add this line to the BasicNetwork class

 if (!ConnectivityUtils.isNetworkEnabled(CardApplication.getContext()) && request instanceof ImageRequest) { VolleyLog.e("Cached response", "No Network Connectivity for Url=", request.getUrl()); return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, request.getCacheEntry().data, responseHeaders, true); } 

and for data expiration you can change Cached.Entry using your own HttpHeaderParser

Here is a link that explains in detail

+2
source

I prefer using Volley / retrofit with Android-Universal-Image-Loader / Picasso , image downloaders did a great job of loading and caching images.

They handle everything with a single line of code by default:

 Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView); 

You can also animate, resize images and add a placeholder at boot time.

+3
source

When you restart the application offline, the last thing you can rely on is Disk Cache only (i.e. DiskBasedCache ). The local volleyball cache consists of network data and response headers. But in this situation, we just need to focus on the Cache-Control header. For example, if the server side returns this header β€œCache-Control: max-age = 604800”, which tells Volley to cache the response resource for 604800 seconds (source HttpHeaderParser.parseCacheHeaders () ). Then the next time we get the same URL data, it will check if the cache expiration time has been exceeded, finally decide to get it from the network or local.

Follow your descriptions, I suppose your server side gives you a value similar to Cache-Control:must-revalidate|proxy-revalidate|no-cache|no-store , so you cannot reuse the last extracted data when you are offline .

At the moment, the question arises: as soon as we can manipulate the cache expiration time, we can increase this time to a sufficiently large value so that we can guarantee that we will use this data offline.

Unfortunately, Volley does not support us in this. So, if you can do the server side to deliver a viable max-age for this?

If not, I suggest you switch to another library that will complete this task. and in fact you may have your friend, Netroid . It is based on Volley and has offered several improvements that will not force you to change your current code drastically. However, managing the expiration time would be much simpler and more features would be available.

 mImageLoader = new SelfImageLoader(mRequestQueue, mLruBitmapCache) { @Override public void makeRequest(ImageRequest request) { // you can manipulate the cache expire time with one line code. request.setCacheExpireTime(TimeUnit.DAYS, 10); // you can even according to the different request to // set up the corresponding expire time. if (request.getUrl().contains("/for_one_day/")) { request.setCacheExpireTime(TimeUnit.DAYS, 1); } else { request.setCacheExpireTime(TimeUnit.DAYS, 10); } } }; 

The full code was in the sample module of the project, I hope this can be useful.

+2
source

Hello @mmlooloo I created a project that uses DiskLRUCache and Volley . Here is the link of my DiskLRUCache repository using Volley . Hope this helps you show the saved image. Thanks.

+1
source
  • Search the web for "android, how to check your internet connection"
  • implement this and check it in your cache implementation (e.g. LruCache ). if(networkAvailable()){ getFromNetwork()} else { getFromCache()}

is logic okay? then just try it.
It seems your cache class is LruBitmapCache .

then how about checking connections in this class?

 public Bitmap getBitmap(String url) { if(networkAvailable()/* this is your impl */){ // dont use cache return null; } return getFromCache(); // or something like that; } 
0
source

If you understand correctly, it will be useful for you if the memory cache provided to the ImageLoader class that your NetworkImageView uses is preserved between application launches, without losing the fact that it is a memory cache.

This memory cache stores the bitmap with the correct size in normal operation - which you want to use even if the network goes down.

So, here is the idea: every time you close the application, save files from the cache. The next time you download the application, when you create a memory cache, check for a constant version on the disk and, if available, fill the memory cache from disk.

There are several approaches that you can decide when to save an image and when to delete it.

Here's one approach: create a hybrid memory / disk cache. It will work just like your memory cache works now with the following differences:

  • Each time putBitmap() is called, along with your usual operation, save the encoded version of the bitmap to disk in the background stream / AsyncTask .
  • Every time a bitmap is removed from the cache (I assume that you have some kind of cache space limitation), delete this file from disk in the background stream / AsyncTask .
  • Create a "loadFromDisk" task that will run in the background each time a memory cache is created (once to run the application) to fill the memory cache with available images from the disk.

You cannot avoid decoding bitmaps, however you can reduce the size and deal with resizing large bitmaps.

Does this help you?

0
source

All Articles