Para explicar la mejora de la implementación decidí utilizar el proyecto que realice en mi primer post.
Me oriento a explicar como facilitar además de la mejora de implementación también los tiempos de desarrollo. En mis proyectos, cuando requiero realizar múltiples Adapters mi estrategia se basa en crear una clase Adapter propia que va a ser la base para mis futuros custom Adapters.
Llegando a quedar de la siguiente forma:
/**
* Base Adapter class for our projects.
*
* @author jonatan.salas
*/
public class BaseListAdapter extends BaseAdapter {
protected Context mContext;
protected List mItems;
/**
* Constructor with parameters.
*
* @param context - the context where this adapter is going to be used.
* @param items - the items to be represented.
*/
public BaseListAdapter(@NonNull final Context context,
@NonNull final List items) {
this.mContext = context;
this.mItems = items;
}
@Override
public int getCount() {
return mItems.size();
}
@Override
public Object getItem(int position) {
return mItems.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return null;
}
/**
* Class that represents a ViewHolder.
*
* @author jonatan.salas
*/
public static abstract class ViewHolder {
/**
* Constructor with parameters.
*
* @param view - the parent view.
*/
protected ViewHolder(@NonNull final View view) {
findViews(view);
}
/**
* Method that finds the widgets we need in our custom item.
*
* @param view - the parent view.
*/
public abstract void findViews(@NonNull final View view);
/**
* Method that binds our widgets with the data.
*
* @param item - Object that has the data to show.
*/
public abstract void bindViews(@NonNull final Object item);
}
}
Como pueden ver ya defino algunos métodos, y además, genero una clase abstracta que define un ViewHolder del cual todos mis Adapters van a extender.En el primer post, luego de Aplicar el patrón ViewHolder mi adapter quedaba de la siguiente forma:
/**
* Custom adapter class
*
* @author jonatan.salas
*/
public class MessageAdapter extends BaseAdapter {
private Context mContext;
private List mItems;
/**
* Constructor with parameters
*
* @param context - the context where the adapter is going to be used.
* @param items - the list of items that the adapter must represent.
*/
public MessageAdapter(@NonNull final Context context,
@NonNull final List items) {
this.mContext = context;
this.mItems = items;
}
public void setItems(List items) {
this.mItems = items;
}
@Override
public int getCount() {
return mItems.size();
}
@Override
public Object getItem(int position) {
return mItems.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
if(null != convertView) {
viewHolder = (ViewHolder) convertView.getTag();
} else {
convertView = LayoutInflater
.from(mContext)
.inflate(R.layout.message_item, parent, false);
viewHolder = new ViewHolder(convertView);
convertView.setTag(viewHolder);
}
onBindViews(viewHolder, position);
return convertView;
}
/**
* Method that bind views with the data to be shown.
*
* @param viewHolder - the viewHolder used to set the data.
* @param position - the position where of the data to get.
*/
private void onBindViews(@NonNull final ViewHolder viewHolder, final int position) {
final MessageContent content = (MessageContent) getItem(position);
viewHolder.profile.setImageDrawable(content.getImage());
viewHolder.name.setText(content.getName());
viewHolder.message.setText(content.getMessage());
viewHolder.hour.setText(content.getHour());
}
/**
* ViewHolder class used for caching the views needed by our adapter.
*
* @author jonatan.salas
*/
protected static class ViewHolder {
private ImageView profile;
private TextView name;
private TextView message;
private TextView hour;
/**
* Constructor with parameters.
*
* @param view - The root view that contains all the views needed.
*/
public ViewHolder(@NonNull final View view) {
profile = (ImageView) view.findViewById(R.id.profile_picture);
name = (TextView) view.findViewById(R.id.contact_name);
message = (TextView) view.findViewById(R.id.message);
hour = (TextView) view.findViewById(R.id.message_hour);
}
}
}
Ahora mi Adapter para mostrar los mensajes queda de la siguiente forma:
/**
* Custom adapter class
*
* @author jonatan.salas
*/
public class MessageAdapter extends BaseListAdapter {
/**
* Constructor with parameters
*
* @param context - the context where the adapter is going to be used.
* @param items - the list of items that the adapter must represent.
*/
public MessageAdapter(@NonNull final Context context,
@NonNull final List items) {
super(context, items);
}
@Override
public View getView(int position, View view, ViewGroup parent) {
final ViewHolder viewHolder;
if(null != view) {
viewHolder = (ViewHolder) view.getTag();
} else {
view = LayoutInflater
.from(mContext)
.inflate(R.layout.message_item, parent, false);
viewHolder = ViewHolder.newInstance(view);
}
viewHolder.bindViews(getItem(position));
return view;
}
/**
* Implementation of ViewHolder
*
* @author jonatan.salas
*/
protected static class ViewHolder extends BaseListAdapter.ViewHolder {
private ImageView profile;
private TextView name;
private TextView message;
private TextView hour;
/**
* Constructor with parameters.
*
* @param view - the parent view.
*/
protected ViewHolder(@NonNull final View view) {
super(view);
}
@Override
public void findViews(@NonNull final View view) {
profile = (ImageView) view.findViewById(R.id.profile_picture);
name = (TextView) view.findViewById(R.id.contact_name);
message = (TextView) view.findViewById(R.id.message);
hour = (TextView) view.findViewById(R.id.message_hour);
view.setTag(this);
}
@Override
public void bindViews(@NonNull final Object item) {
final MessageContent content = (MessageContent) item;
this.profile.setImageDrawable(content.getImage());
this.name.setText(content.getName());
this.message.setText(content.getMessage());
this.hour.setText(content.getHour());
}
/**
* Method that get instances of our ViewHolder class.
*
* @param view - the parent view
* @return a new instance of ViewHolder
*/
public static ViewHolder newInstance(@NonNull final View view) {
return new ViewHolder(view);
}
}
}
Ahora la particularidad de este Adapter, es que deje recaer la responsabilidad del binding de las vistas sobre el ViewHolder. Además de haber reducido cierta porción de código que se volvía reiterativa.
Conclusión:
Cuando los proyectos que tenemos son grandes, es necesario generar una clase Base de la cual podamos extender. También está bueno tener una clase abstracta ViewHolder definida dado a que nos permite mantener el código prolijo en distintas implementaciones de un Adapter.Si deseas aprender un poco más al respecto, he dejado el código del post en un repositorio en Github.
Puedes visualizarlo accediendo a este link.
No hay comentarios:
Publicar un comentario