Skip to content Skip to sidebar Skip to footer

Adapter con carga asíncrona de imágenes (Smooth ListView)

En este post vamos a explicar cómo hacer una correcta implementación de un ListView con un CustomAdapter en el que cada elemento contiene imágenes que se descargarán de manera asíncrona como en la app de Whatsapp.

Vamos a utilizar para el desarrollo del CustomAdapter el patrón ViewHolder con el fin de reutilizar las vistas y que nuestra ListView de un look and feel muy bueno y fluido.

El código del proyecto se podrá descargar desde este enlace:

POCImageAdapter

Antes de nada vamos a crear nuestra ListView en XML y luego vamos a referenciarla desde el código de nuestra Activity, a continuación se puede ver el código de la Activity y todo explicado en los comentarios.

public class MainActivity extends Activity implements OnItemClickListener {

  private ListView mListViewItems;
  private CustomAdapter mAdapter;
  private List mListCategories = new ArrayList();
  private String[] mUrls = {};
  private Random mRandom = new Random();

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

  getViews();
    init();
  }

  private void getViews() {

    mListViewItems = (ListView) findViewById(R.id.listView__activity_main_items);
  }

  private void init() {

    mUrls = getResources().getStringArray(R.array.urls);

    mListViewItems.setOnItemClickListener(this);

    for(int i = 0; i < 50; i++)
      mListCategories.add(new ModelCategory("Item " + i, mUrls[mRandom.nextInt(mUrls.length - 1)]));

    mAdapter = new CustomAdapter(MainActivity.this, mListCategories);
    mListViewItems.setAdapter(mAdapter);
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
  }

  @Override
  public boolean onMenuItemSelected(int featureId, MenuItem item) {

    switch (item.getItemId()) {
      case R.id.action_reset:

        mListCategories = new ArrayList();
        break;
      case R.id.action_add:

        mListCategories.add(new ModelCategory("Object added", mUrls[mRandom.nextInt(mUrls.length - 1)]));
        break;
      case R.id.action_remove:

        if(mListCategories.size() > 0)
          mListCategories.remove(mListCategories.size() - 1);
        break;
      default:
        break;
    }

    mAdapter.setDataset(mListCategories);
    mAdapter.notifyDataSetChanged();

    return true;
  }

  @Override
  public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {

    Toast.makeText(MainActivity.this, mListCategories.get(position).getTitle(), Toast.LENGTH_SHORT).show();
  }

}

Una vez realizado todo esto, vamos a crear nuestro CustomAdapter que extiende de BaseAdapter. Además lo haremos con el patrón ViewHolder que conseguirá reutilizar las vistas de las celdas. Código con comentarios de CustomAdapter:

public class CustomAdapter extends BaseAdapter{

  private List mDataset;
  private LayoutInflater mLayoutInflater;
  private Context mContext;

  public class ViewHolder {

    public ImageView logo;
    public TextView title;
  }

  public CustomAdapter(Context context, List items) {

    mContext = context;
    mLayoutInflater = LayoutInflater.from(context);
    mDataset = items;
  }

  public void setDataset(List newDataset) {

    mDataset = newDataset;
  }

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

  @Override
  public ModelCategory getItem(int position) {
    return mDataset.get(position);
  }

  @Override
  public long getItemId(int position) {
    return position;
  }

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

    ViewHolder holder;
    if(convertView == null) {
      convertView = mLayoutInflater.inflate(R.layout.simple_category_list_item, null);

      holder = new ViewHolder();
      holder.logo = (ImageView) convertView.findViewById(R.id.imageView__simple_category_list_item_logo);
      holder.title = (TextView) convertView.findViewById(R.id.textView__simple_category_list_item_title);
      convertView.setTag(holder);

    } else {

      holder = (ViewHolder)convertView.getTag();
    }

    Picasso.with(mContext).load(getItem(position).getUrl()).into(holder.logo);

    holder.title.setText(getItem(position).getTitle());

    return convertView;
  }
}

Como se puede ver, utilizamos la librería Picasso para la carga asíncrona de imágenes, dicha librería es muy fácil de añadir. Simplemente tenemos que incluir el jar descargable desde la web en la carpeta “libs” y luego con el botón derecho “Build Pathy” –>  “Add to Build Path”.

La forma de utilizarla es mediante un método estático:

  Picasso.with(mContext).load(getItem(position).getUrl()).into(holder.logo);
  • load” puede recibir varios parámetros, en este caso se trata de la url de la imagen a cargar
  • with“, recibe el contexto de la app
  • into“, recibe la ImageView en la que se cargará la imagen
  • También tiene otros métodos para poder setear una imagen de precarga, notificaciones en caso de error y más.

Una vez realizado todo esto solo nos falta añadir el permiso de INTERNET en el manifest para que se puedan descargar las imágenes.

<uses-permission android:name=”android.permission.INTERNET” />

Después de todo esto tendremos nuestro ListView con carga asíncrona de imágenes.

Gracias y espero que sirva de ayuda.

8 Comments

  • Anónimo
    Posted 14 febrero, 2014 at 13:54

    Hello, Neat post. There is a problem with your website in web explorer, could test this? IE still is the market chief and a huge component to other people will omit your excellent writing because of this problem.

    • Post Author
      franlopjurAdmin
      Posted 21 febrero, 2014 at 22:11

      I will try solve this problem, Thanks for your comment!

  • Anónimo
    Posted 17 febrero, 2014 at 15:20

    It’s actually a great and helpful piece of information. I’m glad that you just shared this helpful information with us. Please stay us up to date like this. Thank you for sharing.

  • Anónimo
    Posted 20 febrero, 2014 at 12:34

    I’ve been surfing online greater than three hours nowadays, yet I by no means found any attention-grabbing article like yours. It’s pretty price sufficient for me. In my view, if all web owners and bloggers made excellent content material as you probably did, the web might be much more helpful than ever before.

  • new barbour jacket
    Posted 7 marzo, 2014 at 20:08

    Pretty component of content. I just stumbled upon your blog and in accession capital to assert that I get in fact enjoyed account your weblog posts. Anyway I’ll be subscribing in your feeds or even I success you get admission to consistently rapidly.

  • replica designer bags australia
    Posted 18 marzo, 2014 at 22:29

    Very smooth transaction. Nice product. Thank you.

Comments are closed.