user5363222
user5363222

Reputation:

Recyclerview with multiple view types

I created a recyclerview with multiple view types.First problem is that images don't show and second problem is when i scroll recyclerview, values of its items changes and I don't know how can I fix it. my adapter code:

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

    private ArrayList<DataObject> mDataset;
    Context context;
    RecyclerView.ViewHolder viewHolder;


    public HeterogenousRecyclerviewAdapter(ArrayList<DataObject> myDataset) {
        this.mDataset = myDataset;
    }

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

    @Override
    public int getItemViewType(int position) {
        int view_type=mDataset.get(position).getView_type();
        return view_type;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        context=parent.getContext();
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());

        switch (viewType){
            case 0:
                View v1 = inflater.inflate(R.layout.layout_viewholder1, parent, false);
                viewHolder = new ViewHolder1(v1);
                break;
            case 1:
                View v2 = inflater.inflate(R.layout.layout_viewholder2, parent, false);
                viewHolder = new ViewHolder2(v2);
                break;
        }

        return viewHolder;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

        switch (viewHolder.getItemViewType()){
            case 0:
                ViewHolder1 vh1 = (ViewHolder1) viewHolder;
                configureViewHolder1(vh1, position);
                break;
            case 1:
                ViewHolder2 vh2 = (ViewHolder2) viewHolder;
                configureViewHolder2(vh2, position);
                break;
        }

    }

    private void configureViewHolder1(ViewHolder1 vh1, int position) {
        if (mDataset != null) {
            vh1.getLabel1().setText(mDataset.get(position).getName());
            //vh1.getLabel2().setText("Hometown: " + user.hometown);
        }
    }

    private void configureViewHolder2(ViewHolder2 vh2, int position) {

        //vh2.getImageView().setImageResource(R.mipmap.img1);
        try {
            Resources res = context.getResources();
            int resourceId = res.getIdentifier(mDataset.get(position).getImg(), "mipmap",
                    context.getPackageName());
            vh2.getImageView().setImageResource(resourceId);
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
}

this is my ViewHolder1 class:

public class ViewHolder1 extends RecyclerView.ViewHolder {

    private TextView label1;

    public ViewHolder1(View v) {
        super(v);
        label1 = (TextView) v.findViewById(R.id.text1);
        //label2 = (TextView) v.findViewById(R.id.text2);
    }

    public TextView getLabel1() {
        return label1;
    }

    public void setLabel1(TextView label1) {
        this.label1 = label1;
    }

}

this is ViewHolder1.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">


    <TextView
        android:id="@+id/text1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:textStyle="bold" />

</LinearLayout>

this is ViewHolder2 class:

public class ViewHolder2 extends RecyclerView.ViewHolder {

    private ImageView ivExample;

    public ViewHolder2(View v) {
        super(v);
        ivExample = (ImageView) v.findViewById(R.id.ivExample);
    }

    public ImageView getImageView() {
        return ivExample;
    }

    public void setImageView(ImageView ivExample) {
        this.ivExample = ivExample;
    }
}

this is ViewHolder2.xml:

<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ivExample"
    android:adjustViewBounds="true"
    android:scaleType="fitXY"
    android:layout_width="200dp"
    android:layout_height="200dp"/>

this is my main activity code:

        ArrayList<DataObject> personList = new ArrayList<DataObject>();
        DataObjectDBAdapter dataObjectDBAdapter = new     DataObjectDBAdapter(getApplicationContext());
        personList = dataObjectDBAdapter.getALL();
        adapter = new HeterogenousRecyclerviewAdapter(personList);

        mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
        mLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
        mRecyclerView.setLayoutManager(mLayoutManager);
        mRecyclerView.setAdapter(adapter);

can sb help me?

Upvotes: 1

Views: 4359

Answers (4)

Himanshi Thakur
Himanshi Thakur

Reputation: 2319

While using multiple view types with dynamic data some users may face issues like duplicate data items, data being swapped between questions. To avoid that you have to set a unique view type id for every item.

@Override
public int getItemViewType(int position) {
    // Here you can get decide from your model's ArrayList, which type of view you need to load. Like
    if (list.get(position).type == Something) { // Put your condition, according to your requirements
        return VIEW_TYPE_ONE;
    }
    return VIEW_TYPE_TWO;
}

The above code for getItemViewType can fail where 3 consecutive items will have the same type. For example, if the user enters ans1 in item 1 edit text,ans2 in item 2 edit text, ans3 in item 3 edit text and scroll the recycler view up and down then some users may face issues like duplicate data items, data being swapped between questions.

Formula to create unique view type id :

Formula : pos * Constants.Max + viewType;

set value Constants.Max = 100000;

    class DataAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private final int VIEW_TYPE_EDIT_TEXT = 1;
    private final int VIEW_TYPE_IMAGE_VIEW = 2;
    private final ArrayList<DataModel> dataModelArrayList = new ArrayList<>();

    @Override
    public int getItemViewType(int position) {

        String dataType = dataModelArrayList.get(position).getDataType();
        int viewType = VIEW_TYPE_EDIT_TEXT;

        switch (dataType) {
            case "A":
            case "E":
                viewType = VIEW_TYPE_EDIT_TEXT;
                break;

            case "I":
                viewType = VIEW_TYPE_IMAGE_VIEW;
                break;
        }

        int pos = position + 1;
        return pos * Constants.Max + viewType;

    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int type) {

        int count = (int) Math.ceil(type / Constants.Max);
        int viewType = type - count * Constants.Max;

        if (viewType == VIEW_TYPE_EDIT_TEXT) {
            return new ViewHolderTypeEditText(LayoutInflater.from(context).inflate(R.layout.adapter_status_prompts_et_item, parent, false));
        } else if (viewType == VIEW_TYPE_IMAGE_VIEW) {
            return new ViewHolderTypeImageView(LayoutInflater.from(context).inflate(R.layout.adapter_status_prompts_sp_item, parent, false));
        }

        return new ViewHolderTypeEditText(LayoutInflater.from(context).inflate(R.layout.adapter_status_prompts_et_item, parent, false));

    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int pos) {

        int type = holder.getItemViewType();
        int count = (int) Math.ceil(type / Constants.Max);
        int viewType = type - count * Constants.Max;

        if (viewType == VIEW_TYPE_EDIT_TEXT) {

            DataAdapter.ViewHolderTypeEditText viewHolderTypeEditText = (DataAdapter.ViewHolderTypeEditText) holder;

        } else if (viewType == VIEW_TYPE_IMAGE_VIEW) {

            DataAdapter.ViewHolderTypeImageView viewHolderTypeImageView = (DataAdapter.ViewHolderTypeImageView) holder;

        }

    }

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

    public class ViewHolderTypeEditText extends RecyclerView.ViewHolder {

        EditText etText;

        public ViewHolderTypeEditText(@NonNull View itemView) {
            super(itemView);

            etText = itemView.findViewById(R.id.et_text);


        }
    }

    public class ViewHolderTypeImageView extends RecyclerView.ViewHolder {

        ImageView imageView;


        public ViewHolderTypeImageView(@NonNull View itemView) {
            super(itemView);

            imageView = itemView.findViewById(R.id.image_view);


        }
    }

}

Upvotes: 0

Irfan Yaqub
Irfan Yaqub

Reputation: 140

i had the same problem values changes after the scroll, then i overide these methods

@Override
public long getItemId(int position) {
    return position;
}

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

This solved my problem and for the Image heck the image resourceId is null or not i am not sure if your way is good to set the Resource.

Upvotes: 0

user5363222
user5363222

Reputation:

I hadn't saved names of images in the SQLite database so the first problem was because of that, and the second problem was in my adapter code. I had to write "viewHolder" instead of "holder" in onBindViewHolder(), so the correct method is:

@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {

    switch (viewHolder.getItemViewType()){
        case 0:
            ViewHolder1 vh1 = (ViewHolder1) viewHolder;
            configureViewHolder1(vh1, position);
            break;
        case 1:
            ViewHolder2 vh2 = (ViewHolder2) viewHolder;
            configureViewHolder2(vh2, position);
            break;
    }

}

Upvotes: 1

Zar E Ahmer
Zar E Ahmer

Reputation: 34390

First make sure the given statement must only return 0 or 1. because view type must start with 0

int view_type=mDataset.get(position).getView_type();

No need to create the below viewHolder as a member of class

RecyclerView.ViewHolder viewHolder;

Don't check viewType in onBindViewHolder . Instead check holder instanceOf

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

        if(holder instanceOf ViewHolder1){
            (ViewHolder1) holder.getLabel1().setText(mDataset.get(position).getName());
        }
        else
        {
            try {
                Resources res = context.getResources();
                int resourceId = res.getIdentifier(mDataset.get(position).getImg(), "mipmap",
                    context.getPackageName());
                (ViewHolder2) holder.getImageView().setImageResource(resourceId);
            } catch (Exception e) {}
        }
    }

Upvotes: 0

Related Questions