Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Hetrogenenous recyclerview jerk and data model confusion

I have a RecyclerView containing Horizontal RecyclerView and Vertical Recyclerview. I am confused about how to manage Data model for both. Here is my code followed by this example

public class HomeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private final int VIEW_TYPE_DESIGN_TYPES = 0;
    private final int VIEW_TYPE_DESIGNS = 1;

    private Context context;
    private ArrayList<Object> feeds;

    public HomeAdapter(Context context, ArrayList<Object> feeds) {
        this.context = context;
        this.feeds = feeds;
    }

    @Override
    public int getItemViewType(int position) {
        if (position == 0)
            return VIEW_TYPE_DESIGN_TYPES;
        if (position == 1)
            return VIEW_TYPE_DESIGNS;
        return -1;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(context);
        View view;
        RecyclerView.ViewHolder holder;
        switch (viewType) {
            case VIEW_TYPE_DESIGN_TYPES:
                view = inflater.inflate(R.layout.item_home_design_types, parent, false);
                holder = new DesignTypesViewHolder(view);
                break;
            case VIEW_TYPE_DESIGNS:
                view = inflater.inflate(R.layout.item_home_designs, parent, false);
                holder = new DesignsViewHolder(view);
                break;
            default:
                view = inflater.inflate(R.layout.item_home_designs, parent, false);
                holder = new DesignsViewHolder(view);
                break;
        }
        return holder;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (holder.getItemViewType() == VIEW_TYPE_DESIGN_TYPES)
            designTypesView((DesignTypesViewHolder) holder);
        else if (holder.getItemViewType() == VIEW_TYPE_DESIGNS)
            designsView((DesignsViewHolder) holder);
    }


    private void designTypesView(DesignTypesViewHolder holder) {
        HomeAdapterDesignTypes homeAdapterDesignTypes = new HomeAdapterDesignTypes(getDesignTypes());
        holder.recyclerView.setAdapter(homeAdapterDesignTypes);
    }

    private void designsView(DesignsViewHolder holder) {
        HomeAdapterDesigns homeAdapterDesigns = new HomeAdapterDesigns(getDesigns());
        holder.recyclerView.setAdapter(homeAdapterDesigns);
    }

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

    public void updateFeeds(ArrayList<Object> mFeeds) {
        feeds.addAll(mFeeds);
        notifyDataSetChanged();
    }

    public class DesignTypesViewHolder extends RecyclerView.ViewHolder {
        RecyclerView recyclerView;
        DesignTypesViewHolder(View itemView) {
            super(itemView);
            recyclerView = itemView.findViewById(R.id.rvHomeDesignTypes);
            recyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false));
            ItemOffsetDecoration itemDecoration = new ItemOffsetDecoration(context, R.dimen.item_offset);
            recyclerView.addItemDecoration(itemDecoration);
        }
    }

    public class DesignsViewHolder extends RecyclerView.ViewHolder {
        RecyclerView recyclerView;
        DesignsViewHolder(View itemView) {
            super(itemView);
            recyclerView = itemView.findViewById(R.id.rvHomeDesigns);
            recyclerView.setLayoutManager(new GridLayoutManager(context, 2));
            int spanCount = 2;
            int spacing = 15;
            boolean includeEdge = true;
            recyclerView.addItemDecoration(new GridSpacingItemDecoration(spanCount, spacing, includeEdge));
        }
    }

    private ArrayList<DesignType> getDesignTypes() {
        ArrayList<DesignType> singleHorizontals = new ArrayList<>();
        for(int i = 0 ; i < feeds.size(); i++) {
            Object object = feeds.get(i);
            if(object instanceof DesignType) {
                singleHorizontals.add((DesignType) object);
            }
        }
        return singleHorizontals;
    }

    private ArrayList<Design> getDesigns() {
        ArrayList<Design> singleVerticals = new ArrayList<>();
        for(int i = 0 ; i < feeds.size(); i++) {
            Object object = feeds.get(i);
            if(object instanceof Design) {
                singleVerticals.add((Design) object);
            }
        }
        return singleVerticals;
    }
}

Now my Horizontal recyclerview is at position 0 and has static data items. Vertical RecyclerView is dynamic and I want to implement endless scroll for it. I dont know how to manage and update Data Model (POJO class) for both. Because Object type for both Recyclerviews are different. Should I create a common POJO class for both?

Another issue I am facing is that there is a jerk when list scrolls at the end.

like image 236
Nouman Bhatti Avatar asked Nov 06 '22 19:11

Nouman Bhatti


1 Answers

Looks like your parent recycler-view is designed to contain only two items:

@Override
public int getItemViewType(int position) {
    if (position == 0)
        return VIEW_TYPE_DESIGN_TYPES;
    if (position == 1)
        return VIEW_TYPE_DESIGNS;
    return -1;
}

But from here I can see that if you have more then two items - you will end up having all subsequent holders created as DesignsViewHolder:

default:
            view = inflater.inflate(R.layout.item_home_designs, parent, false);
            holder = new DesignsViewHolder(view);
            break;

If the intent was - to have the top level recycler view with horizontal scroll and the next recycler view within grid items, then its pretty ok to have just two recycler views within one layout.

<ConstraintLayout or ScrollView> - as u wish
  <RecyclerView\> - horizontal one
  <RecyclerView\> - vertical one, or with grid layout manager
<\ConstraintLayout or ScrollView>

EDIT: On the attached to your question link we have a vice versa structure. Vertical scroll and the last item with horizontal scroll. In such case u can switch the recycler-views ordering.

Still if you wanna have truly different items inside your recycler view its worth considering having the Adapter Delegates pattern.

Pay attention: having a lot of different scroll directions inside recycler view is not easy to maintain. Sometimes diff bugs occur, which are hardly fixable. In some cases it is easier to end up having a scroll view inside a recycler view, instead of recycler view inside recycler-view. RecyclerView has a pretty complicated structure under the hood, which optimizes performance and items reusability. In most cases u need something simple with 5-10 items for horizontal scroll in terms of mixing this layout with vertical scroll. A lot of things to discuss here, really case dependent.

Have a look at Joe's problem and a nice GitHub lib, those should help with Adapters Delegate pattern understanding. Good luck!

like image 86
Yurii Tsap Avatar answered Nov 11 '22 12:11

Yurii Tsap