Recyclerview ViewHolder:onCreateViewHolder,视图绑定和onBindViewHolder在同一个类中

时间:2016-08-30 23:43:33

标签: android android-recyclerview android-viewholder

RecyclerView.ViewHolder中,视图被传递给构造函数。此视图是一个膨胀的布局。 RecyclerView.ViewHolder仅使用findViewById绑定视图。

RecyclerView.Adapter的角色为:

  • onCreateViewHolder
  • 中夸大了布局
  • 将ViewHolder与包含onBindViewHolder
  • 的数据集绑定

我有几个RecyclerViews显示相同的数据列表。我希望每个RecyclerView与各自的ViewHolder显示不同。我的目标是为每个RecyclerView使用相同的通用RecyclerView.Adapter。 因此必须将ViewHolder传递给此RecyclerView.Adapter。 我试图实现一个可以实现所有3种方法的ViewHolder。 知道如何实现这个目标吗?

我看了不同的项目。到目前为止最好的,AdapterDelegates可以解决这个问题。但是你仍然需要处理AdapterDelegate和ViewHolder类。如何在同一个班级中将两者结合起来? (没有内部课程)

3 个答案:

答案 0 :(得分:2)

正如所承诺的,我创建了一个新的答案,它不使用反射。它在技术上使用两个类(工厂类和持有者类),而不是一个,但它们是相同的。代码经过测试,有效。

  

MyAdapter.java

public class MyAdapter extends RecyclerView.Adapter<MyViewHolder>
{
    List<Object> _data;
    MyViewHolder.Factory _factory;

    MyAdapter(List data, MyViewHolder.Factory factory)
    {
        _data = data;
        _factory = factory;
        if (_data == null || _factory == null)
        {
            throw new NullPointerException("Both data and factory cannot be null!");
        }
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
    {
        return _factory.createViewHolder(parent, viewType);
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position)
    {
        holder.bindViewHolder(_data.get(position));
    }

    @Override
    public int getItemCount()
    {
        return _data.size();
    }
}
  

MyViewHolder.java

public abstract class MyViewHolder extends RecyclerView.ViewHolder
{
    public interface Factory
    {
        public abstract MyViewHolder createViewHolder(ViewGroup parent, int viewType);
    }

    public MyViewHolder(View itemView)
    {
        super(itemView);
    }

    public abstract void bindViewHolder(Object data);
}
  

MainActivity.java

public class MainActivity extends AppCompatActivity
{

    static class NameViewHolder extends MyViewHolder
    {
        // If preferred, the following can be created anonymously in code
        static class Factory implements MyViewHolder.Factory
        {
            @Override
            public MyViewHolder createViewHolder(ViewGroup parent, int viewType)
            {
                View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.main_recycler_item, parent, false);
                return new NameViewHolder(v);
            }
        };

        TextView tv;
        NameViewHolder(View v)
        {
            super(v);
            tv = (TextView)v.findViewById(R.id.textView);
        }

        @Override
        public void bindViewHolder(Object data)
        {
            tv.setText((String)data);
        }
    }


    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View view)
            {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });

        RecyclerView rv = (RecyclerView)findViewById(R.id.my_recycler_view);
        rv.setHasFixedSize(true);

        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        rv.setLayoutManager(layoutManager);

        ArrayList<String> data = new ArrayList();
        for (int i = 1; i < 100; ++i)
            data.add(Integer.toString(1000 + i));

        MyAdapter adapter = new MyAdapter(data, new NameViewHolder.Factory());
        rv.setAdapter(adapter);
    }

}

答案 1 :(得分:1)

我建议创建一个抽象的ViewHolder父Class。它应该具有静态即时方法和bindViewHolder方法。设计适配器构造函数以接受ViewHolder父Class对象。使用时,传递子Class对象,在onCreateViewHolder中,使用Reflection创建子ViewHolder。当你得到一个onBindViewHolder时,只需将它传递给ViewHolder。

这是一个工作示例。我测试了它,它工作了。我删除了非必要的代码。

  

MainActivity.java

public class MainActivity extends AppCompatActivity
{

    static class NameViewHolder extends MyViewHolder
    {
        TextView tv;
        public static MyViewHolder instantate(ViewGroup parent, int viewType)
        {
            View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.main_recycler_item, parent, false);
            MyViewHolder vh = new NameViewHolder(v);
            return vh;
        }
        NameViewHolder(View v)
        {
            super(v);
            tv = (TextView)v.findViewById(R.id.textView);
        }

        @Override
        public void bindViewHolder(Object data)
        {
            tv.setText((String)data);
        }
    }


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

        RecyclerView rv = (RecyclerView)findViewById(R.id.my_recycler_view);
        rv.setHasFixedSize(true);

        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        rv.setLayoutManager(layoutManager);

        ArrayList<String> data = new ArrayList();
        for (int i = 1; i < 100; ++i)
            data.add(Integer.toString(1000 + i));
        MyAdapter adapter = new MyAdapter(data, NameViewHolder.class);
        rv.setAdapter(adapter);
    }
}
  

MyViewHolder.java

public abstract class MyViewHolder extends RecyclerView.ViewHolder
{
    // The following has to be declared in sub class. As Java 7 does not support static interface, we commented it out here
    //public static MyViewHolder instantate(ViewGroup parent, int viewType);

    public MyViewHolder(View itemView)
    {
        super(itemView);
    }
    public abstract void bindViewHolder(Object data);
}
  

MyAdapter.java

public class MyAdapter extends RecyclerView.Adapter<MyViewHolder>
{
    List<Object> _data;
    Class _holderClass;

    MyAdapter(List data, Class holderClass)
    {
        _data = data;
        _holderClass = holderClass;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
    {
        MyViewHolder vh = null;
        try
        {
            Class[] cArg = {ViewGroup.class, int.class};
            Method instantateMethod = _holderClass.getMethod("instantate", cArg);
            vh = (MyViewHolder) instantateMethod.invoke(null, parent, viewType);
        }
        catch (NoSuchMethodException e)
        {
            e.printStackTrace();
        }
        catch (InvocationTargetException e)
        {
            e.printStackTrace();
        }
        catch (IllegalAccessException e)
        {
            e.printStackTrace();
        }
        return vh;
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position)
    {
        holder.bindViewHolder(_data.get(position));
    }

    @Override
    public int getItemCount()
    {
        return _data.size();
    }

}

答案 2 :(得分:0)

您可以将R.layout传递给RVadapter

static int layoutResource;

public RVadapter(Context context, int id) {
    layoutResource = id;
}

然后您可以在ViewHolder中执行此操作

if(RVadapter.layoutResource == R.layout.message_layout) {
            message_view = (CardView) itemView.findViewById(R.id.card_message);
            message_image = (ImageView) itemView.findViewById(R.id.message_image);
            message_name = (TextView) itemView.findViewById(R.id.messenger);
            message_details = (TextView) itemView.findViewById(R.id.details);
        }
        else if(RVadapter.layoutResource == R.layout.guide_layout){
            guide_name = (TextView) itemView.findViewById(R.id.new_travel_name);
            guide_gendr_age = (TextView) itemView.findViewById(R.id.new_travel_gender_age);
            guide_tours = (TextView) itemView.findViewById(R.id.new_travel_tour);
            rb = (RatingBar) itemView.findViewById(R.id.new_travel_rb);
        }