【问题标题】:Generic adapter for many kinds of listview 's layout row in androidandroid中多种listview布局行的通用适配器
【发布时间】:2012-10-24 17:05:04
【问题描述】:

对于每个具有不同行布局模板的列表视图,我必须创建每个自定义适配器,它们做同样的事情:加载 xml 行布局,通过 id 获取控制(TextView、ImageView 等)、显示数据......像这样:

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;
}
}

对于多种列表视图(差异行布局模板),我必须创建许多适配器。
所以,问题是我想创建一个模板适配器,它可以是动态加载行xml,基于它的id映射视图控件(可能使用反射)。行xml布局、控件id、视图控件将在其他地方定义。
有没有design pattern、example或framework可以做到这一点?

【问题讨论】:

  • 我会为此研究策略设计模式。
  • 由于适配器的全部目的是在数据和视图之间进行转换,如果您想使用不同的行布局,我认为您不能避免 getView 中的逻辑。
  • @toadzky 我不回避get view中的逻辑,我只想用view属性一个一个映射数据(映射表可以在其他地方定义)。但这只是我的想法,我还没有实现。
  • 在这里查看我的答案。 stackoverflow.com/a/38350061/3496570

标签: android design-patterns listview android-adapter


【解决方案1】:

这样的事情似乎是可行的。我根本没有测试过这个,但理论上你可以摆脱这样的事情:

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));
}

我可能完全忽略了一些不起作用的原因 - 我在五分钟内输入了这个。不过,理论上我认为它会起作用。

【讨论】:

  • 非常感谢。我试过你的方法,但我做的有点复杂,现在它就像一个魅力。你可以看看我的回答。
【解决方案2】:

我尝试了kcoppock的方式,但我做的有点复杂。
首先,我创建了一个 ViewHolder,它可以通过使用注解与视图 id 进行映射。

public class MobileViewHolder {

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

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

然后,我可以使用反射将 ViewHolder 中的字段映射到视图 ID:

   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));

    }

之后,我只是将数据从实体绑定到 ViewHolder。

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

结论:这样,对于多种不同的行布局模板的列表视图,我只需要4件事:

  • 行 xml 文件
  • ViewHolder:定义视图控件和视图属性
  • 实体
  • Item 视图:扩展 BaseView 以及 ViewHolder 和 Entity 之间的映射逻辑数据。

这是我测试过的source code 示例:)

【讨论】:

  • 对这种方法的工作原理有何反馈?我有兴趣尝试在新项目中实施这种方法。
  • 好吧,我已经好几年没处理这个代码了。我将此代码发布到我的博客中,似乎有问题,但现在我没有时间。对不起。 ductranit.blogspot.com/2012/10/…
猜你喜欢
  • 2015-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多