2

I have a list view. Displayed as a card view. In card view I have an image which I want to change dynamically based on object TYPE. So for that I have created two different layouts which contain small and big image. I have created an adapter and tried to inflate two different layouts in onCreateViewHolder.I am getting a Null pointer exception on these lines of code. No idea what I am missing...Please Help..

itemViewHolder.big.setImageDrawable(drawable1);
  itemViewHolder.small.setImageDrawable(drawable);
public class IAdapter extends RecyclerView.Adapter<IAdapter.ItemViewHolder> {

Adapter code

    public class ItemAdapter extends RecyclerView.Adapter<IAdapter.ItemViewHolder> {

    List<Expense> items;
    public static final int TYPE1 = 1;
    public static final int TYPE2 = 2;

    IAdapter(List<Expense> items) {

        this.items = items;

    }

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

    }

    @Override
    public int getItemViewType(int position) {

        Expense e = new Expense();
        if (TYPE1 == 1) {
            int type = e.getExpenseType();
            return type;
        } else {
            return TYPE2;
        }

    }

    @Override
    public void onBindViewHolder(ItemViewHolder itemViewHolder, int i) {

        itemViewHolder.amount.setText(items.get(i).amount);
        itemViewHolder.expense.setText(items.get(i).expense);
        TextDrawable drawable = TextDrawable.builder()
                .beginConfig()
                .withBorder(4)
                .textColor(Color.BLACK)
                .useFont(Typeface.DEFAULT)
                .fontSize(25)
                .bold()
                .toUpperCase()
                .endConfig()
                .buildRound("11:00", Color.GRAY);
        itemViewHolder.small.setImageDrawable(drawable);

        TextDrawable drawable1 = TextDrawable.builder()
                .beginConfig()
                .withBorder(4)
                .textColor(Color.BLACK)
                .useFont(Typeface.DEFAULT)
                .fontSize(25)
                .bold()
                .toUpperCase()
                .endConfig()
                .buildRound("10 Jan", Color.CYAN);
        itemViewHolder.big.setImageDrawable(drawable1);

    }

    @Override
    public ItemViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {

        if (viewType == TYPE1) {
            View itemView = LayoutInflater.
                    from(viewGroup.getContext()).
                    inflate(R.layout.cardlayout, viewGroup, false);
            return new ItemViewHolder(itemView, viewType);
        } else {
            View itemView = LayoutInflater.
                    from(viewGroup.getContext()).
                    inflate(R.layout.bigcircle, viewGroup, false);
            ItemViewHolder ivh = new ItemViewHolder(itemView, viewType);
            return ivh;
        }
    }

    public static class ItemViewHolder extends RecyclerView.ViewHolder {
        CardView cv;
        TextView amount;
        TextView expense;
        ImageView small;
        ImageView big;

        ItemViewHolder(View itemView, int viewType) {
            super(itemView);
            amount = (TextView) itemView.findViewById(R.id.txtAmount);
            expense = (TextView) itemView.findViewById(R.id.txtexpense);
            cv = (CardView) itemView.findViewById(R.id.card_view);
            small = (ImageView) itemView.findViewById(R.id.small);
            big=(ImageView)itemView.findViewById(R.id.big);
            //   cv1 = (CardView) itemView.findViewById(R.id.card_view);

            //TextDrawable drawable1 = TextDrawable.builder()
            // .buildRound("20 Jan", Color.RED);

        }
    }


    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
    }

}

cardlayout code

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="1"
android:orientation="vertical"
android:measureWithLargestChild="false"
android:background="@android:color/white">
<!-- A CardView that contains a TextView -->

<android.support.v7.widget.CardView
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card_view"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    card_view:cardCornerRadius="4dp"
    android:background="@android:color/white">


    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/relativeLayout"
        android:background="@android:color/white"
        android:layout_alignParentTop="true">


        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:id="@+id/txtAmount"
            android:text="text1"
            android:layout_centerVertical="true"
            android:layout_toLeftOf="@+id/linearLayout"
            android:layout_toStartOf="@+id/linearLayout"
            android:layout_marginRight="24dp"
            android:layout_marginEnd="24dp" />

        <LinearLayout
            android:orientation="vertical"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:weightSum="1"
            android:id="@+id/linearLayout"
            android:gravity="center_vertical"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true">


            <ImageView
                android:layout_width="40dp"
                android:layout_height="25dp"
                android:id="@+id/imageView2"
                android:background="@drawable/line" />

            <ImageView

                android:id="@+id/small"
                android:focusableInTouchMode="false"
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:background="@drawable/circle"/>


            <ImageView
                android:layout_width="40dp"
                android:layout_height="25dp"
                android:id="@+id/imageView3"
                android:background="@drawable/line" />
        </LinearLayout>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:text="Medium Text"
            android:id="@+id/txtexpense"
            android:layout_centerVertical="true"
            android:layout_toRightOf="@+id/linearLayout"
            android:layout_toEndOf="@+id/linearLayout"
            android:layout_marginLeft="24dp"
            android:layout_marginStart="24dp" />
    </RelativeLayout>

</android.support.v7.widget.CardView>

bigcircle card layout code

  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:weightSum="1"
    android:orientation="vertical"
    android:measureWithLargestChild="false">
    <!-- A CardView that contains a TextView -->

    <android.support.v7.widget.CardView
        xmlns:card_view="http://schemas.android.com/apk/res-auto"
        android:id="@+id/card_view1"
        android:layout_width="match_parent"
        android:layout_height="80dp"
        card_view:cardCornerRadius="4dp"
        android:background="@android:color/white">


        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/relativeLayout"
            android:background="@android:color/white"
            android:layout_alignParentTop="true">


            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceMedium"
                android:id="@+id/txtAmount"
                android:text="text1"
                android:layout_centerVertical="true"
                android:layout_toLeftOf="@+id/linearLayout"
                android:layout_toStartOf="@+id/linearLayout"
                android:layout_marginRight="24dp"
                android:layout_marginEnd="24dp" />

            <LinearLayout
                android:orientation="vertical"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:weightSum="1"
                android:id="@+id/linearLayout"
                android:gravity="center_vertical"
                android:layout_alignParentTop="true"
                android:layout_centerHorizontal="true">


                <ImageView
                    android:layout_width="50dp"
                    android:layout_height="25dp"
                    android:id="@+id/imageView2"
                    android:background="@drawable/line" />

                <ImageView

                    android:id="@+id/big"
                    android:focusableInTouchMode="false"
                    android:layout_width="50dp"
                    android:layout_height="50dp"
                    android:background="@drawable/circle1"/>


                <ImageView
                    android:layout_width="50dp"
                    android:layout_height="25dp"
                    android:id="@+id/imageView3"
                    android:background="@drawable/line" />
            </LinearLayout>

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceMedium"
                android:text="Medium Text"
                android:id="@+id/txtexpense"
                android:layout_centerVertical="true"
                android:layout_toRightOf="@+id/linearLayout"
                android:layout_toEndOf="@+id/linearLayout"
                android:layout_marginLeft="24dp"
                android:layout_marginStart="24dp" />
        </RelativeLayout>

    </android.support.v7.widget.CardView>
</LinearLayout>

What am I missing???

diyoda_
  • 5,274
  • 8
  • 57
  • 89

3 Answers3

1

It is because you are using the ItemViewHolder that is passed from the onCreateViewHoldermethod inside the onBindViewHoldermethod. The reason it fails is that, You have 2 different inflated views passed one containing view element with id big and the other with id small. So, either itemViewHolder.big or itemViewHolder.small becomes null. That throws an NullPointerException

I think the way you approached this is correct.

Option One: This is a different way of achieving this.

if you have completely different layouts for these two, you have to do it this way. But if the layout of the cards are the same only those big and small images are changing, I suggest you to keep a single layout and change the image view grammatically.

Option Two

Your approach. I suggest you to stick to it because that is the elegant way of doing this. But you will have to do some minor tweaks.

    @Override
    public int getItemViewType(int position) {
          return items.get(position).getExpenseType();// Assume that this return 1 0r 2
    }

I suggest you to check the type before you set the value here, Assuming that you have a TYPE class variable to keep the Type for each item.

@Override
    public void onBindViewHolder(ItemViewHolder itemViewHolder, int i) {

       itemViewHolder.amount.setText(items.get(i).amount);
       itemViewHolder.expense.setText(items.get(i).expense);

       if(getItemViewType(i) == 1){
        TextDrawable drawable = TextDrawable.builder()
                .beginConfig()
                .withBorder(4)
                .textColor(Color.BLACK)
                .useFont(Typeface.DEFAULT)
                .fontSize(25)
                .bold()
                .toUpperCase()
                .endConfig()
                .buildRound("11:00", Color.GRAY);
        itemViewHolder.small.setImageDrawable(drawable);
       }else{
        TextDrawable drawable1 = TextDrawable.builder()
                .beginConfig()
                .withBorder(4)
                .textColor(Color.BLACK)
                .useFont(Typeface.DEFAULT)
                .fontSize(25)
                .bold()
                .toUpperCase()
                .endConfig()
                .buildRound("10 Jan", Color.CYAN);
        itemViewHolder.big.setImageDrawable(drawable1);
      }
    }

This has not changed my answer. But this will give you a good idea. The cavity thing that you are missing is in this,

public static class ItemViewHolder extends RecyclerView.ViewHolder {
        CardView cv;
        TextView amount;
        TextView expense;
        ImageView small;
        ImageView big;

        ItemViewHolder(View itemView, int viewType) {
            super(itemView);
            amount = (TextView) itemView.findViewById(R.id.txtAmount);
            expense = (TextView) itemView.findViewById(R.id.txtexpense);
            cv = (CardView) itemView.findViewById(R.id.card_view);
            small = (ImageView) itemView.findViewById(R.id.small);
            big=(ImageView)itemView.findViewById(R.id.big);
            //   cv1 = (CardView) itemView.findViewById(R.id.card_view);

            //TextDrawable drawable1 = TextDrawable.builder()
            // .buildRound("20 Jan", Color.RED);

        }
    }

even though you do

small = (ImageView) itemView.findViewById(R.id.small);
big=(ImageView)itemView.findViewById(R.id.big);

either small or big variable will get assigned null. But you have to check that before calling a method on it. Otherwise it will give a NullPointerException

Edit:

Or you can do,

@Override
public ItemViewHolder onCreateViewHolder(ViewGroup viewGroup,int viewType) {

    View itemView;
    if (getItemViewType(i)==1) {
        itemView = LayoutInflater.
                from(viewGroup.getContext()).
                inflate(R.layout.cardlayout, viewGroup, false);

    } else {
        itemView = LayoutInflater.from(viewGroup.getContext()).
                inflate(R.layout.bigcircle, viewGroup, false);
    }

    return new ItemViewHolder(itemView,viewType);
}
diyoda_
  • 5,274
  • 8
  • 57
  • 89
  • thank you for reply.. Can you plz explain me the right code?? –  Aug 28 '15 at 18:15
  • I have two different layouts. so based on type i want to inflate layouts. Is that code of setting image might be at wrong place??? –  Aug 28 '15 at 18:36
  • I have referred this link but unable to implement in my code. can u help me out plz.. http://stackoverflow.com/questions/25914003/recyclerview-and-handling-different-type-of-row-inflation –  Aug 28 '15 at 18:38
  • But i want size difference in two images so I thought of different cards. How can i change size of image in same card?? –  Aug 28 '15 at 18:43
  • still i am confused with this. can you plz show me the proper code.? –  Aug 28 '15 at 18:59
  • @user3623979 are you still confused. :) – diyoda_ Aug 28 '15 at 19:01
  • @user3623979 can you tell me which part you do not understand? – diyoda_ Aug 28 '15 at 19:05
  • for this line if(getItemViewType()==1) its shoeing getItemViewType cannot be applied to 0 –  Aug 28 '15 at 19:18
  • @user3623979 I have made a mistake there it has to `begetItemViewType(i)`. does it still give this – diyoda_ Aug 28 '15 at 19:23
  • yes it resolved that issue. But what shouls i do in onCreateViewHolder to inflate two layouts?? –  Aug 28 '15 at 19:26
  • as u suggested if(getItemViewType()==1) { small = (ImageView) itemView.findViewById(R.id.small); }else{ big=(ImageView)itemView.findViewById(R.id.big); } is it right?? –  Aug 28 '15 at 19:27
  • Thank you so much for help.. I got the desired result by doing some more changes.. –  Aug 28 '15 at 19:49
0

@Override public ItemViewHolder onCreateViewHolder(ViewGroup viewGroup,int viewType) {

    if (getItemViewType(i)==1) {
        View itemView = LayoutInflater.
                from(viewGroup.getContext()).
                inflate(R.layout.cardlayout, viewGroup, false);
        return new ItemViewHolder(itemView,viewType);
    } else {
        View itemView = LayoutInflater.from(viewGroup.getContext()).
                inflate(R.layout.bigcircle, viewGroup, false);
        ItemViewHolder ivh = new ItemViewHolder(itemView, viewType);
        return ivh;
    }
}

is this right??

0
public class IAdapter extends RecyclerView.Adapter<IAdapter.ItemViewHolder> {

    List<Expense> items;
    public static final int TYPE1=1;



    IAdapter(List<Expense> items) {

        this.items = items;

    }

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

    }

    @Override
        public int getItemViewType(int position) {
            return items.get(position).getExpenseType();// Assume that this return 1 0r 2
        }

    @Override
    public void onBindViewHolder(ItemViewHolder itemViewHolder, int i) {

        itemViewHolder.amount.setText(items.get(i).amount);
        itemViewHolder.expense.setText(items.get(i).expense);
    }

    @Override
    public ItemViewHolder onCreateViewHolder(ViewGroup viewGroup,int viewType) {

        if (viewType==TYPE1) {
            View itemView = LayoutInflater.
                    from(viewGroup.getContext()).
                    inflate(R.layout.cardlayout, viewGroup, false);
            return new ItemViewHolder(itemView,viewType);
        } else {
            View itemView = LayoutInflater.from(viewGroup.getContext()).
                    inflate(R.layout.bigcircle, viewGroup, false);
            ItemViewHolder ivh = new ItemViewHolder(itemView, viewType);
            return ivh;
        }
    }


    public static class ItemViewHolder extends RecyclerView.ViewHolder {
        CardView cv;
        TextView amount;
        TextView expense;
        ImageView small;
        ImageView big;

        ItemViewHolder(View itemView, int viewType) {
            super(itemView);
            amount = (TextView) itemView.findViewById(R.id.txtAmount);
            expense = (TextView) itemView.findViewById(R.id.txtexpense);
            cv = (CardView) itemView.findViewById(R.id.card_view);

            if(viewType==TYPE1) {
                small = (ImageView) itemView.findViewById(R.id.small);
                TextDrawable drawable = TextDrawable.builder()
                        .beginConfig()
                        .withBorder(4)
                        .textColor(Color.BLACK)
                        .useFont(Typeface.DEFAULT)
                        .fontSize(25)
                        .bold()
                        .toUpperCase()
                        .endConfig()
                        .buildRound("11:00", Color.GRAY);
                small.setImageDrawable(drawable);
            }else{
                big=(ImageView)itemView.findViewById(R.id.big);
                TextDrawable drawable = TextDrawable.builder()
                        .beginConfig()
                        .withBorder(4)
                        .textColor(Color.BLACK)
                        .useFont(Typeface.DEFAULT)
                        .fontSize(25)
                        .bold()
                        .toUpperCase()
                        .endConfig()
                        .buildRound("10Jan", Color.CYAN);
                big.setImageDrawable(drawable);
            }

            //   cv1 = (CardView) itemView.findViewById(R.id.card_view);

            //TextDrawable drawable1 = TextDrawable.builder()
            // .buildRound("20 Jan", Color.RED);

        }
    }


    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
    }

}

this is giving the desired result..