Skip to content Skip to sidebar Skip to footer

Recyclerview Viewholder : Oncreateviewholder , View Binding And Onbindviewholder In The Same Class

In RecyclerView.ViewHolder , a view is passed to the constructor. This view is an inflated layout. The RecyclerView.ViewHolder only bind the views with findViewById. The RecyclerVi

Solution 1:

As promised I have created a new answer, which does not use reflection. It technically uses two classes (a factory class and a holder class), not one, but is just the same. The code is tested, and it works.

MyAdapter.java

publicclassMyAdapterextendsRecyclerView.Adapter<MyViewHolder>
{
    List<Object> _data;
    MyViewHolder.Factory _factory;

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

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

    @OverridepublicvoidonBindViewHolder(MyViewHolder holder, int position)
    {
        holder.bindViewHolder(_data.get(position));
    }

    @OverridepublicintgetItemCount()
    {
        return _data.size();
    }
}

MyViewHolder.java

publicabstractclassMyViewHolderextendsRecyclerView.ViewHolder
{
    publicinterfaceFactory
    {
        publicabstract MyViewHolder createViewHolder(ViewGroup parent, int viewType);
    }

    publicMyViewHolder(View itemView)
    {
        super(itemView);
    }

    publicabstractvoidbindViewHolder(Object data);
}

MainActivity.java

publicclassMainActivityextendsAppCompatActivity
{

    staticclassNameViewHolderextendsMyViewHolder
    {
        // If preferred, the following can be created anonymously in codestaticclassFactoryimplementsMyViewHolder.Factory
        {
            @Overridepublic MyViewHolder createViewHolder(ViewGroup parent, int viewType)
            {
                Viewv= LayoutInflater.from(parent.getContext()).inflate(R.layout.main_recycler_item, parent, false);
                returnnewNameViewHolder(v);
            }
        };

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

        @OverridepublicvoidbindViewHolder(Object data)
        {
            tv.setText((String)data);
        }
    }


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

        FloatingActionButtonfab= (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(newView.OnClickListener()
        {
            @OverridepublicvoidonClick(View view)
            {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });

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

        LinearLayoutManagerlayoutManager=newLinearLayoutManager(this);
        rv.setLayoutManager(layoutManager);

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

        MyAdapteradapter=newMyAdapter(data, newNameViewHolder.Factory());
        rv.setAdapter(adapter);
    }

}

Solution 2:

I would suggest creating an abstract ViewHolder parent Class. It should have a static instantate method and a bindViewHolder method. Design the Adapter constructor to accept the ViewHolder parent Class object. When used, pass the child Class Object, and in onCreateViewHolder, use Reflection to create the child ViewHolder. When you get an onBindViewHolder, just pass it to the ViewHolder.

Here is a working example. I tested it, and it worked. I have removed non-essential code.

MainActivity.java

publicclassMainActivityextendsAppCompatActivity
{

    staticclassNameViewHolderextendsMyViewHolder
    {
        TextView tv;
        publicstatic MyViewHolder instantate(ViewGroup parent, int viewType)
        {
            Viewv= LayoutInflater.from(parent.getContext()).inflate(R.layout.main_recycler_item, parent, false);
            MyViewHoldervh=newNameViewHolder(v);
            return vh;
        }
        NameViewHolder(View v)
        {
            super(v);
            tv = (TextView)v.findViewById(R.id.textView);
        }

        @OverridepublicvoidbindViewHolder(Object data)
        {
            tv.setText((String)data);
        }
    }


    @OverrideprotectedvoidonCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

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

        LinearLayoutManagerlayoutManager=newLinearLayoutManager(this);
        rv.setLayoutManager(layoutManager);

        ArrayList<String> data = newArrayList();
        for (inti=1; i < 100; ++i)
            data.add(Integer.toString(1000 + i));
        MyAdapteradapter=newMyAdapter(data, NameViewHolder.class);
        rv.setAdapter(adapter);
    }
}

MyViewHolder.java

publicabstractclassMyViewHolderextendsRecyclerView.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);publicMyViewHolder(View itemView)
    {
        super(itemView);
    }
    publicabstractvoidbindViewHolder(Object data);
}

MyAdapter.java

publicclassMyAdapterextendsRecyclerView.Adapter<MyViewHolder>
{
    List<Object> _data;
    Class _holderClass;

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

    @Overridepublic MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
    {
        MyViewHoldervh=null;
        try
        {
            Class[] cArg = {ViewGroup.class, int.class};
            MethodinstantateMethod= _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;
    }

    @OverridepublicvoidonBindViewHolder(MyViewHolder holder, int position)
    {
        holder.bindViewHolder(_data.get(position));
    }

    @OverridepublicintgetItemCount()
    {
        return _data.size();
    }

}

Solution 3:

You can by making passing R.layout to your RVadapter

staticint layoutResource;

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

then you can do this in your 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);
        }
        elseif(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);
        }

Post a Comment for "Recyclerview Viewholder : Oncreateviewholder , View Binding And Onbindviewholder In The Same Class"