Reputation: 2769
I am using RecyclerView.Adapter but I am little confused regarding working of its method onCreateViewHolder
.
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
if(viewType==TYPE_ITEM) {
View mView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.inflate_common_item, viewGroup, false);
ViewHolder vh = new ViewHolder(mView);
return vh;
} else {
View mView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.inflate_uncommon_item, viewGroup, false);
ViewHolderFooter vh = new ViewHolderFooter(mView);
return vh;
}
}
So incase I have 10 items in my list so for each item this method will be called and every time a new ViewHolder
will be created of course it'll one time for each view but now my question is when we were using ListView
and BaseAdapter
with them we store ViewHolder
in tag and use that. We don't create ViewHolder
for each item.
@Override
public View getView(int position, View convertView, ViewGroup parent) {
MyViewHolder mViewHolder;
if(convertView == null) {
convertView = inflater.inflate(R.layout.layout_list_item, null);
mViewHolder = new MyViewHolder();
convertView.setTag(mViewHolder);
} else {
mViewHolder = (MyViewHolder) convertView.getTag();
}
mViewHolder.tvTitle = detail(convertView, R.id.tvTitle, myList.get(position).getTitle());
mViewHolder.tvDesc = detail(convertView, R.id.tvDesc, myList.get(position).getDescription());
mViewHolder.ivIcon = detail(convertView, R.id.ivIcon, myList.get(position).getImgResId());
return convertView;
}
So are we not creating extra viewholders object. Please help me understand the pros and cons.
Thanks
Upvotes: 15
Views: 46764
Reputation: 4956
You can use this :
--> Create a constructor :
/** * Created by Deepak Sharma on 31/10/17. */
public class StoreListAdapter<T> extends RecyclerView.Adapter<StoreListAdapter.ViewHolder> implements Filterable {
private Collection<T> mItems;
private Context context;
private int mLayout;
IClickable iClickable;
private boolean isAnimationAllowed;
private StoreSearchFilter<T> mSearchFilter;
public StoreListAdapter(Context context)
{
this.context = context;
}
public void setData(Collection<T> items, boolean isAnimationAllowed)
{
mItems = items;
this.isAnimationAllowed = isAnimationAllowed;
}
public void setCallback(int layout, IClickable iClickable)
{
this.mLayout = layout;
this.iClickable = iClickable;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(mLayout, viewGroup, false);
iClickable.init(view);
StoreListAdapter.ViewHolder viewHolder = new StoreListAdapter.ViewHolder(view);
view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
int width = view.getMeasuredWidth();
int height = view.getMeasuredHeight();
// viewHolder.itemView.getLayoutParams().width = width;
viewHolder.itemView.getLayoutParams().height = height+24;
return viewHolder;
}
@Override
public void onBindViewHolder(StoreListAdapter.ViewHolder viewHolder, int i) {
iClickable.execute(viewHolder, mItems.toArray()[i],viewHolder.getAdapterPosition());
if (isAnimationAllowed)
setAnimation(viewHolder.itemView, i);
}
@Override
public int getItemCount() {
return mItems.size()>0?mItems.size():0;
}
@Override
public Filter getFilter() {
if (mSearchFilter == null)
mSearchFilter = new StoreSearchFilter<T>((ArrayList<StoreModel>) mItems, new IFilteredList<T>() {
@Override
public void onListFiltered(ArrayList<T> list) {
setData(list, false);
notifyDataSetChanged();
}
});
return mSearchFilter;
}
public class ViewHolder extends RecyclerView.ViewHolder {
private final TextView mTextView;
//private CheckBox mCheckBox;
ViewHolder(View v) {
super(v);
mTextView = (TextView)v.findViewById(R.id.list_item);
// Handle item click and set the selection
/*v.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Redraw the old selection and the new
notifyItemChanged(selectedItem);
selectedItem = getLayoutPosition();
notifyItemChanged(selectedItem);
}
});*/
}
}
public interface IClickable<T> {
public void init(View view);
public void execute(StoreListAdapter.ViewHolder holder, T object, int position);
}
/**
* Here is the key method to apply the animation
*/
private void setAnimation(View viewToAnimate, int position)
{
Animation animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left);
viewToAnimate.startAnimation(animation);
}
}
--> In you Activity/Fragment :
ArrayList<StoreModel> mStoreList = new ArrayList<>();
mStoreListAdapter = new StoreListAdapter(getActivity());
boolean isAnimate = false;
mStoreListAdapter.setData(mStoreList, isAnimate);
then call callback
mStoreListAdapter.setCallback(R.layout.store_item, new StoreListAdapter.IClickable() {
@Override
public void init(View view) {
// Toast.makeText(getActivity(), "Initialized", Toast.LENGTH_SHORT).show();
}
@Override
public void execute(StoreListAdapter.ViewHolder viewHolder, Object object, int position) {
final StoreModel model = (StoreModel) object;
View view = viewHolder.itemView;
StoreListAdapter.ViewHolder holder = viewHolder;
final CoordinatorLayout fabGameview = (CoordinatorLayout) view;
final CardView cardView = (CardView) fabGameview.findViewById(R.id.store_item_cardview);
TextView txtStoreName = (TextView) cardView.findViewById(R.id.txtStoreName);
TextView txtStoreAddress = (TextView) cardView.findViewById(R.id.txtStoreAddress);
TextView txtStoreCity = (TextView) cardView.findViewById(R.id.txtStoreCity);
TextView txtPrizes = (TextView) cardView.findViewById(R.id.txtPrizes);
txtStoreName.setText(model.getStoreName());
txtStoreAddress.setText(model.getStoreAddress());
txtStoreCity.setText(model.getStoreCity());
txtPrizes.setText(String.valueOf(model.getPrizesAvailable()));
LinearLayout linearDetails = (LinearLayout) cardView.findViewById(R.id.linearDetails);
LinearLayout linearPrize = (LinearLayout) cardView.findViewById(R.id.linearPrize);
if (clickedMarkerModel != null && clickedMarkerModel == model) {
holder.itemView.setSelected(true);
// holder.itemView.setPressed(true);
// linearDetails.setBackgroundColor(getResources().getColor(R.color.colorPrimaryDark));
// linearPrize.setBackgroundColor(getResources().getColor(R.color.colorPrimaryDark));
// mRecyclerStore.stopScroll();
} else {
holder.itemView.setSelected(false);
// holder.itemView.setPressed(false);
// linearDetails.setBackground(ContextCompat.getDrawable(getActivity(), R.drawable.store_selector));
// linearPrize.setBackground(ContextCompat.getDrawable(getActivity(), R.drawable.store_selector));
}
// TODO Here scroll recycler view upto selected item
/*mRecyclerStore.smoothScrollToPosition(mStoreListAdapter.getItemCount() - 1);*/
cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean isAddedToBackStack = true;
StoreDetailsAndProductListFragment storeDetailsAndProductListFragment = new StoreDetailsAndProductListFragment();
Bundle bundle = new Bundle();
bundle.putParcelable(ExtrasUtil.STORE, model);
storeDetailsAndProductListFragment.setArguments(bundle);
showOtherFragment(storeDetailsAndProductListFragment, getActivity().getFragmentManager(), isAddedToBackStack);
}
});
}
});
mRecyclerStore.setAdapter(mStoreListAdapter);
Upvotes: 0
Reputation: 16781
onCreateViewHolder
only creates a new view holder when there are no existing view holders which the RecyclerView
can reuse. So, for instance, if your RecyclerView
can display 5 items at a time, it will create 5-6 ViewHolders
, and then automatically reuse them, each time calling onBindViewHolder
.
Its similar to what your code in the ListView
does (checking if convertView
is null
, and if not, grabbing the existing ViewHolder
from the tag), except, with RecyclerView
, this is all done automatically.
I suppose this is one of the pros with using a RecyclerView
- you don't need to worry so much about reusing ViewHolders
as you do with ListView
. The con is, RecyclerView
is very customisable, but has very little built in functionality - unlike ListView
which is not very customisable, but has a lot of built in functionality.
Upvotes: 24