Ravers
Ravers

Reputation: 1039

Storing ListView Images in cache

I have a ListView with more than 100 items and each item has a different image. The images are already in the drawable folder, so I'm not requesting to any server.

When I scroll the ListView since the phone has to render each image again, sometimes it gets a little slow, seems like low fps. For test purposes I used the same image for all items, and the scroll was much better, so I think the problem is indeed the different images needed to being rendered.

My question is: can I store those images on cache or something to make this scroll smother? Here is my ListView Adapter code:

public class AdapterItens extends BaseAdapter implements ListAdapter {

    private final JSONArray jsonArray;

    static class ViewHolder {
        ImageView itemAvatar;
        TextView itemName;
        TextView itemId;
    }

    public AdapterItens(JSONArray jsonArray) {
        this.jsonArray = jsonArray;
    }

    @Override
    public int getCount() {
        return jsonArray.length();
    }

    @Override
    public JSONObject getItem(int position) {
        return jsonArray.optJSONObject(position);
    }

    @Override
    public long getItemId(int position) {
        JSONObject jsonObject = getItem(position);
        return jsonObject.optLong("id");
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final ViewHolder viewHolder;

        if (convertView == null) {
             final LayoutInflater inflater = LayoutInflater.from(Controller.getContext());
             convertView = inflater.inflate(R.layout.item_layout, parent, false);

             viewHolder = new ViewHolder();
             viewHolder.itemAvatar = (ImageView) convertView.findViewById(R.id.avatar_item);
             viewHolder.itemName = (TextView) convertView.findViewById(R.id.name_item);
             viewHolder.itemId = (TextView) convertView.findViewById(R.id.id_item);

             convertView.setTag(viewHolder);
        } else {
             viewHolder = (ViewHolder) convertView.getTag();
        }

        final JSONObject jsonData = getItem(position);
        viewHolder.itemAvatar.setImageResource(Controller.getContext().getResources().getIdentifier(jsonData.getString("itemAvatar"), "drawable", Controller.getContext().getPackageName()));
        viewHolder.itemName.setText(jsonData.getString("itemName"));
        viewHolder.itemId.setText(jsonData.getString("itemId"));

        return convertView;
    }
}

Upvotes: 0

Views: 135

Answers (2)

Alex Kamenkov
Alex Kamenkov

Reputation: 891

I suppose the problem is that you parse JSON "on fly". First of all parse JSON into list with objects inside AsyncTask, each object will contain id, name and bitmap.

For example:

class YourObjectName {
    long id;
    String name;
    Bitmap bitmap;
}

Your code will looks like this:

static class ViewHolder {
    ImageView itemAvatar;
    TextView itemName;
    TextView itemId;
}

public ItemsAdapter (List<YourObjectName> yourObjectsList) {
    this.yourObjectsList = yourObjectsList;
}

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

@Override
public YourObjectName getItem(int position) {
    return yourObjectsList.get(position);
}

@Override
public long getItemId(int position) {
    return yourObjectsList.get(position).id;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    final ViewHolder viewHolder;
    if (convertView == null) {
        final LayoutInflater inflater = LayoutInflater.from(Controller.getContext());
        convertView = inflater.inflate(R.layout.item_layout, parent, false);

        viewHolder = new ViewHolder();
        viewHolder.itemAvatar = (ImageView) convertView.findViewById(R.id.avatar_item);
        viewHolder.itemName = (TextView) convertView.findViewById(R.id.name_item);
        viewHolder.itemId = (TextView) convertView.findViewById(R.id.id_item);

        convertView.setTag(viewHolder);
    } else {
        viewHolder = (ViewHolder) convertView.getTag();
    }

    YourObjectName itemAtPosition = yourObjectsList.get(position);
    viewHolder.itemAvatar.setImageBitmap(itemAtPosition.bitmap);
    viewHolder.itemName.setText(itemAtPosition.name);
    viewHolder.itemId.setText(itemAtPosition.id);

    return convertView;
}

Finally, you can use library like Glide or Picasso to load your pictures in background.

Just replace this line with one of this library, and instead bitmap save drawable_id.

viewHolder.itemAvatar.setImageBitmap(itemAtPosition.bitmap);

Glide: https://github.com/bumptech/glide

Glide.with(context)
      .load(itemAtPosition.drawable_id)
      .resize(width, height)
      .centerCrop()
      .into(viewHolder.itemAvatar);

Picasso: http://square.github.io/picasso/

Picasso.with(context)
       .load(itemAtPosition.drawable_id)
       .override(width, height)
       .centerCrop()
       .into(viewHolder.itemAvatar);

Also it's highly recommended to use recyclerview instead listview, take a look on the accepted answer. Android Recyclerview vs ListView with Viewholder

Upvotes: 1

blkrt
blkrt

Reputation: 297

you can use Universal Image Loader library to Cache your images and clear it when

loaded many images to flow your listview :

https://github.com/nostra13/Android-Universal-Image-Loader

Upvotes: 0

Related Questions