7

For each list view with difference row layout template, I must create each custom adapter, which do the same thing: load xml row layout, get control (TextView, ImageView, etc..) by id, display data... something like this:

public class CommentAdapter extends BaseAdapter {

protected Activity activity;
protected static LayoutInflater layoutInflater = null;  
protected List<Comment> lst;    

public CommentAdapter(Activity activity,  List<Comment> lst){
    this.activity = activity;       
    this.lst = lst;
    layoutInflater = (LayoutInflater)this.activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

public int getCount() {     
    return lst.size();
}

public Object getItem(int position) {   
    return lst.get(position);
}

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

public static class ViewHolder{
    public TextView textName;
    public TextView textComment;
    public ImageView image;
}

public  View getView(int position, View convertView, ViewGroup parent) {
    View v = convertView;
    ViewHolder viewHolder;
    if (v == null) {
        v = layoutInflater.inflate(R.layout.listitem, null);
        viewHolder = new ViewHolder();
        viewHolder.textName = (TextView) v.findViewById(R.id.txtName);
        viewHolder.image = (ImageView) v.findViewById(R.id.icon);
        viewHolder.textComment = (TextView)v.findViewById(R.id.txtComment);
        v.setTag(viewHolder);
    } else {
        viewHolder = (ViewHolder) v.getTag();
    }
    Static.overrideFonts(v);
    viewHolder.image.setBackgroundResource(lst.get(position).Icon);
    viewHolder.textName.setText(lst.get(position).Name);
    viewHolder.textComment.setText(lst.get(position).Comment);

    return v;
}
}

With many kind of list view (difference row layout template), I have to create many adapters.
So, the question is that I want to create one template adapter, which can be dynamic load row xml, map view control base on its id (maybe use reflect). The row xml layout, the control id, view control will be defined in another places.
Is there any design pattern, example or framework can achieve this?

ductran
  • 10,043
  • 19
  • 82
  • 165
  • I'd look into the Strategy design pattern for that. – Kevin Coppock Oct 24 '12 at 17:09
  • since the entire purpose of an adapter is to translate between the data and the view, i don't think you can avoid the logic in getView if you want to use different row layouts. – toadzky Oct 24 '12 at 17:47
  • @toadzky I don't avoid logic in get view, I just want to map data with view property one by one (the map table can be defined in another place). But it's only my idea, I haven't implemented it. – ductran Oct 25 '12 at 08:25
  • have a look at my Answer here. http://stackoverflow.com/a/38350061/3496570 – Zar E Ahmer Feb 03 '17 at 13:29

2 Answers2

8

Something like this seems doable. I haven't tested this at all, but in theory you could get away with something like this:

public interface Adaptable {
    //Interface that any object you make that should be put in a listview
    //should implement
    public View buildView(View v, LayoutInflater inflater);
    public int getLayoutId();
}

public class MyObject implements Adaptable
    //Just hardcode your layout for this type of object
    public int getLayoutId() {
        return R.layout.myLayout;
    }

    //getView() will pass the recycled view to this method
    //which will handle building the view per this object
    public View buildView(View v, LayoutInflater inflater) {
        if(v == null) {
            v = inflater.inflate(getLayoutId());
            //Other initialization
        } //other initialization

        return v;
    }
}

//Then make the generic adapter that handles anything that implements
//the Adaptable interface
public GenericAdapter implements ListAdapter {
    private LayoutInflater inflater;
    private List<Adaptable> items;
    public GenericAdapter(List<Adaptable> items, Context c) {
        this.items = items;
        inflater = LayoutInflater.from(c);
    }

    //Now, using polymorphism, it should return a correctly built
    //view for whatever object type you've passed in.
    @Override
    public View getView(int pos, View convertView, ViewGroup parent) {
        return items.get(pos).buildView(convertView, inflater);
    }
}

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    List<MyObject> objects = new ArrayList<MyObject>();
    //Fill your list however.

    //get your ListView, then...
    listView.setAdapter(new GenericAdapter(object, this));
}

It's possible I've totally overlooked some reason this wouldn't work -- I typed this up in five minutes. In theory I think it would work, though.

Kevin Coppock
  • 133,643
  • 45
  • 263
  • 274
  • Thanks you very much.I tried your way, but I do a little more complicated, now it works like a charm. You can check my answer. – ductran Oct 25 '12 at 18:37
2

I tried the way of kcoppock, but I do a little more complicated.
First, I create an ViewHolder which can be map with view id by using annotation.

public class MobileViewHolder {

    @InvokeView(viewId = R.id.label)
    public TextView text;

    @InvokeView(viewId = R.id.logo)
    public ImageView image;
}

Then, I can map field in ViewHolder with view id by using reflect:

   Field fs[] = viewHolder.getClass().getFields();
        for (Field f : fs) {
            InvokeView a = (InvokeView)f.getAnnotation(InvokeView.class);
            int id = a.viewId();
            f.set(viewHolder, v.findViewById(id));

    }

After that, I just binding data from an entity to ViewHolder.

  public void mappingData(MobileViewHolder viewHolder, Mobile entity) {
    viewHolder.text.setText(entity.name);
    viewHolder.image.setBackgroundResource(entity.image);
}

Conclusion: in this way, for many kinds of list view which difference row layout template, I just need 4 things:

  • Row xml file
  • ViewHolder: define the view control and view property
  • Entity
  • Item view: extends the BaseView and mapping logic data between ViewHolder and Entity.

And here is an source code sample that I have tested :)

ductran
  • 10,043
  • 19
  • 82
  • 165
  • Any feedback on how this approach is working? I am interested to try and implement this approach in a new project. – Zapnologica Oct 03 '14 at 18:09
  • Well, I haven't worked on this code for years. I posted this code into my blog, seem there is a problem with it, but now I don't have time for it. Sorry. http://ductranit.blogspot.com/2012/10/generic-adapter-for-all-listview-in.html – ductran Oct 04 '14 at 11:40