Question

I have been trying to implement LruCache in my app but I have difficulties connecting the dots and passing Bitmaps between the different components.

I would like to know how to integrate LruCache in my app. I am also looking to understand the process of implementing the LruCache so the more details the better

The first class is the AsyncTask Image Loader and the second class is my custom adapter

AsyncTask

 public class GetImagesBitmap extends AsyncTask<ImageView, Void, Bitmap>{
    InputStream inputStream;
    ImageView imageView = null;
    String path;




    @Override
    protected Bitmap doInBackground(ImageView... imageViews) {
        this.imageView = imageViews[0];
        return download_Image((String)imageView.getTag());
    }

    @Override
    protected void onPostExecute(Bitmap result) {

        imageView.setImageBitmap(result);
    }

    private Bitmap download_Image(String url) {


        final AndroidHttpClient client = AndroidHttpClient.newInstance("Android");
        HttpGet httpGet = new HttpGet(url);
        try {
            HttpResponse httpResponse = client.execute(httpGet);
            final int statusCode = httpResponse.getStatusLine().getStatusCode();
            if (statusCode != HttpStatus.SC_OK) {
                Log.w("ImageDownloader", "Error " + statusCode
                        + " while retrieving bitmap from " + url);
                return null;
            }

            final HttpEntity entity = httpResponse.getEntity();
            if(entity != null){
                inputStream = null;
                inputStream = entity.getContent();
                final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                return bitmap;
            }
                if(inputStream != null){
                    inputStream.close();
                }
                entity.consumeContent();

        } catch (IOException e) {

            httpGet.abort();
             Log.w("ImageDownloader", "Error while retrieving bitmap from " + url);
        }finally{
            if(client != null){
                client.close();
            }
        }

        return null;
        }



    }

Custom view adapter class

 public class CustomListingListAdapter extends ArrayAdapter<HashMap<String, String>> {





    private ArrayList<HashMap<String, String>> data;
    private Context context;
    private LayoutInflater mInflater;
    private int viewId;
    private String[] tag;
    HashMap<String, String> currentData = new HashMap<String, String>();

    //private static final String TAG_CONTENT = "content";
    //private static final String TAG_RATING = "rating";
    private static final String TAG_NAME = "name";
    private static final String TAG_IMAGE_PATH = "image_path";
    private static final String TAG_PRODUCT_ID = "product_id";
    private static final String TAG_RATING = "rating";

    public CustomListingListAdapter(Context c,
            ArrayList<HashMap<String, String>> data,
            int viewId, String[] tag) {
        super( c, viewId, data);

        this.context = c;
        this.data= data;
        this.viewId = viewId ;
    }

    @Override
    public int getCount() {

        return data.size();
    }

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

        View vi = convertView;
        Holder holder;

        if (convertView == null) {

            // Inflate the view since it does not exist
            if (vi == null) {
                mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                vi = mInflater.inflate(R.layout.list_item_layout, null);

            }

            holder = new Holder();

            holder.Name = (TextView) vi.findViewById(R.id.name);
            holder.pid = (TextView) vi.findViewById(R.id.pid);
            holder.imageView = (ImageView) vi.findViewById(R.id.list_image);
            holder.ratingView = (ImageView) vi.findViewById(R.id.num_stars);

            vi.setTag(holder);  
        }else {
            holder = (Holder) vi.getTag();
        }


        currentData = (HashMap<String, String>) data.get(position);
        holder.imageView.setTag(currentData.get(TAG_IMAGE_PATH));





        if (currentData != null) {

            holder.Name.setText(currentData.get(TAG_NAME));
            holder.pid.setText(currentData.get(TAG_PRODUCT_ID));
        }   

        new GetImagesBitmap().execute(holder.imageView);
    return vi;


    }
    private static class Holder {

        public ImageView imageView;
        public ImageView ratingView;
        public TextView pid;
        public TextView Name;

       } 
    }
Was it helpful?

Solution

You're on the right track, but I couldn't tell where in your code you account for view recycling in your List/GridView. You are indeed reusing the convertView passed to getView, but launching a new AsyncTask in every getView will lead to the tasks loading the images, but then inserting them in the wrong list rows if the view it was started by gets recycled. My advice would be to check out Volley, Google's new networking library. It has a NetworkImageView class that will load an image asynchronously into an ImageView. The reason I recommend it is caching, both on disk and in memory, and view recycling are handled for you.

Volley: https://developers.google.com/events/io/sessions/325304728

If you do want to tackle this on your own, I would check out the Android Developer blog post about loading bitmaps in a ListView. It demonstrated using AsyncTasks like you want to do, but it correctly handles view recycling.

Article: http://developer.android.com/training/displaying-bitmaps/process-bitmap.html

Last little tip: don't instantiate a new HttpClient for every network call. Creating one takes some time and the preferred method is to keep one HttpClient, configured for multi threading, as a Singleton instance and use it for your network calls. Alternatively, you could create a new HttpUrlConnection for each request; that is okay for that class.

EDIT: Sorry, I just realized I didn't actually answer the question. To implement an LruCache for Bimaps, you can extend the LruCache class from the Support Library with a few adjustments. Here's a class I've used for caching Bitamps for use with the Volley library:

// From com.android.volley.toolbox.ImageLoader
public interface ImageCache {
    public Bitmap getBitmap(String url);
    public void putBitmap(String url, Bitmap bitmap);
}

// My ImageCache implementation
public class BitmapLruCache extends LruCache<String, Bitmap> implements ImageCache {
    private static final int DEFAULT_CACHE_SIZE = (int) (Runtime.getRuntime().maxMemory() / 1024) / 8;

    public BitmapLruCache() {
        this(DEFAULT_CACHE_SIZE);
    }

    public BitmapLruCache(int maxSize) {
        super(maxSize);
    }

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

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

    @Override
    protected int sizeOf(String key, Bitmap value) {
        return value == null ? 0 : value.getRowBytes() * value.getHeight() / 1024;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top