Ishan hrx Ishan hrx - 3 years ago 95
Java Question

Null pointer Exception in RecyclerViewAdapter

The adapter was working just fine until I decided to add Native Ads, for that I made 6 changes in the adapter.


  1. added new ViewType (AD_VIEW_TYPE)

  2. added new ViewHolder (NativeExpressAdViewHolder)

  3. changed getItemViewType (made it return AD_VIEW_TYPE at every 8th position)

  4. added a new case in onCreateViewHolder

    switch (viewType){

    case AD_VIEW_TYPE:
    View nativeExpressLayoutView = LayoutInflater.from(parent.getContext())
    .inflate(R.layout.native_express_ad_container, parent, false);
    return new NativeExpressAdViewHolder(nativeExpressLayoutView);

  5. Added a new case to onBindViewHolder

    switch (viewType){

    case AD_VIEW_TYPE:
    NativeExpressAdViewHolder nativeExpressHolder = (NativeExpressAdViewHolder)holder;
    NativeExpressAdView adView = (NativeExpressAdView)arrayList.get(position);

    ViewGroup adCardView = (ViewGroup)nativeExpressHolder.itemView;
    adCardView.removeAllViews();

    if(adView.getParent() != null){
    ((ViewGroup)adView.getParent()).removeView(adView);
    }

    adCardView.addView(adView);
    break;

  6. Other than the above changes, I also changed my
    ArrayList<CardSetterGetter>
    to
    ArrayList<Object>
    in Activity and Adapter too.



Now the problem is that when I run the app, it throws
NullPointerException
.

the logcat says

java.lang.NullPointerException: Attempt to invoke virtual method 'void android.view.View.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
at com.company.appname.adapters.RecyclerViewAdapter$RecyclerViewHolder.<init>(RecyclerViewAdapter.java:186)
at com.company.appname.adapters.RecyclerViewAdapter$RecyclerViewHolder.<init>(RecyclerViewAdapter.java:165)
at com.company.appname.adapters.RecyclerViewAdapter$NativeExpressAdViewHolder.<init>(RecyclerViewAdapter.java:150)
at com.company.appname.adapters.RecyclerViewAdapter.onCreateViewHolder(RecyclerViewAdapter.java:84)
at com.company.appname.adapters.RecyclerViewAdapter.onCreateViewHolder(RecyclerViewAdapter.java:48)


These are the part of my code where the logcat is pointing to

/*Line 48*/public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.RecyclerViewHolder> {
public RecyclerViewAdapter(Context context, ArrayList<Object> arrayList, ArrayList<String> favouriteItemList, int totalCount {...}

@Override
public long getItemId(int position){...}

@Override
public RecyclerViewAdapter.RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

switch (viewType){

case AD_VIEW_TYPE:
View nativeExpressLayoutView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.native_express_ad_container, parent, false);
/*Line 84*/ return new NativeExpressAdViewHolder(nativeExpressLayoutView);

case MENU_ITEM_VIEW_TYPE:

default:
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.cards, parent, false);
return new RecyclerViewHolder(view);
}
}

@Override
public void onBindViewHolder(final RecyclerViewHolder holder, final int position){...}

public class NativeExpressAdViewHolder extends RecyclerViewHolder{
NativeExpressAdViewHolder(View view){
/*Line 150*/ super(view);
}
}

@Override
public int getItemViewType(int position){...}

@Override
public int getItemCount(){...}


/*Line 165*/ public class RecyclerViewHolder extends RecyclerView.ViewHolder {

TextView title;
RelativeLayout relativeLayout;
RelativeLayout cardDescription;
SimpleDraweeView image;
ImageView favourite_button;
CardSetterGetter cardSetterGetter;
ImageView share;


private RecyclerViewHolder(View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.image_title);
relativeLayout = (RelativeLayout) itemView.findViewById(R.id.activity_dash_board);
cardDescription = (RelativeLayout) itemView.findViewById(R.id.card_details);
image = (SimpleDraweeView) itemView.findViewById(R.id.image);
favourite_button = (ImageView) itemView.findViewById(R.id.favourite_button);
share = (ImageView) itemView.findViewById(R.id.share);

/*Line 186*/ image.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {

Activity activity = (Activity) context;
saveInfo(constants.SERVERIP.concat(cardSetterGetter.getImageurl()), cardSetterGetter.getImageId(), cardSetterGetter.getDescription(), cardSetterGetter.getImagetitle(), cardSetterGetter.getFavourite());
Intent i = new Intent().setClass(context, DetailsImageviewActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
context.startActivity(i);
activity.overridePendingTransition(R.anim.pull_from_right, R.anim.pull_out_to_right);
}
});

}
}
}


I know what a NullPointerException is, I know the solution to those problems, but in this case it's getting hard for me to find the source and the solution of the problem. So if the solution is that simple, instead of marking the question as a duplicate, please consider helping me out with this.

ken ken
Answer Source

When come to inflate 2 different view type in a recyclerView,we need to create 2 separate ViewHolder class to contain the different element inside of each layout

Try the following:

//make this a separate class,but not inside the onBindViewHolder
private class NativeExpressAdViewHolder extends RecyclerView.ViewHolder{
    NativeExpressAdViewHolder(View view){                            
    super(view);
    //find the view here
    adView = (NativeExpressAdView)view.findViewById(R.id.native_ad);
}

private class RecyclerViewHolder extends RecyclerView.ViewHolder{
   //this one as usual..
}



//change your onCreateViewHolder for this as well,
// cause now you have 2 view type,so you just override from universal 
//RecyclerView.ViewHolder,not need RecyclerViewAdapter.RecyclerViewHolder
   @Override
     public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { }




@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    int viewType = getItemViewType(position);
    switch (viewType){
      case AD_VIEW_TYPE:
      final NativeExpressAdViewHolder adHolder (NativeExpressAdViewHolder)holder
       //here find your view and load the ad


     break;
     case MENU_ITEM_VIEW_TYPE:
     final  RecyclerViewHolder viewHolder = (RecyclerViewHolder)holder
     //do your thing here,find view,assign value to the layout

    }

And one more thing,please check your XML,your XML should look like this

<com.google.android.gms.ads.NativeExpressAdView
        xmlns:ads="http://schemas.android.com/apk/res-auto"
        android:id="@+id/native_ad"
        android:layout_gravity="center_horizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        ads:adSize="360x132"
        ads:adUnitId="@string/your_ads">

 </com.google.android.gms.ads.NativeExpressAdView>
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download