简体   繁体   中英

Android RecyclerView.Adapter onCreateViewHolder() working

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

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM