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:
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
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.
franlopjurAdmin
I will try solve this problem, Thanks for your comment!
Anónimo
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.
franlopjurAdmin
Thanks for your comment!
Anónimo
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.
franlopjurAdmin
Thanks for your comment!
new barbour jacket
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
Very smooth transaction. Nice product. Thank you.
Comments are closed.