Daniel Einars Daniel Einars - 28 days ago 9
Android Question

RecyclerView inside CardView inside RecyclerView throwing null pointer on findViewById

I'm trying to have a RecyclerView, where each row is a CardLayout, which again contains a RecyclerView (with Header, Items and Footer). I have tried to instansiate the innerRecyclerView in the OnBind from the OuterRecyclerView but keep on getting a nullpointer.

"Main" Activity Code:

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.Window;
import android.view.WindowManager;

import com.squareup.timessquare.CalendarPickerView;

import java.util.List;

import ch.zhaw.it15a_zh.psit3_03.mealmanager.R;
import ch.zhaw.it15a_zh.psit3_03.mealmanager.adapters.OuterWeekplanAdapter;
import ch.zhaw.it15a_zh.psit3_03.mealmanager.db.repos.UserPlannedRecipesRepo;
import ch.zhaw.it15a_zh.psit3_03.mealmanager.models.UserPlannedRecipe;

public class WeekPlanActivity extends AppCompatActivity {
private RecyclerView outerRecyclerView;
private CalendarPickerView calendar;
private UserPlannedRecipesRepo uprr = new UserPlannedRecipesRepo();
private List<UserPlannedRecipe> userPlannedRecipeList;
private List<String> distinctUserPlannedDates;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Hide Top Toolbar form android device
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
//Set LayoutFile
setContentView(R.layout.activity_weekplan);
/* BEGIN TOOLBAR */
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar_weekplan_overview);
setSupportActionBar(toolbar);
getSupportActionBar().setTitle(R.string.toolbar_title_weekplan_activity);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
/* END TOOLBAR */

outerRecyclerView = (RecyclerView) findViewById(R.id.activity_weekplan_outer_recyclerview);
distinctUserPlannedDates = uprr.getDistinctListOfPlannedDates();

OuterWeekplanAdapter outerWeekplanAdapter =
new OuterWeekplanAdapter(getApplicationContext(), distinctUserPlannedDates);

RecyclerView.LayoutManager manager = new LinearLayoutManager(getApplicationContext());
outerRecyclerView.setLayoutManager(manager);
outerRecyclerView.setItemAnimator(new DefaultItemAnimator());
outerRecyclerView.setAdapter(outerWeekplanAdapter);

}

//Inflate Options Menu to show additional buttons in toolbar
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_weekplan_main_menu, menu);
return super.onCreateOptionsMenu(menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.ic_action_weekplan_add:
Intent intent = new Intent(this, DateRangePicker.class);
Context context = this;
context.startActivity(intent);
}
return super.onOptionsItemSelected(item);
}


}


Inner RecyclerView Adapter

import android.content.Context;
import android.net.Uri;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.squareup.picasso.Picasso;

import java.util.List;

import ch.zhaw.it15a_zh.psit3_03.mealmanager.R;
import ch.zhaw.it15a_zh.psit3_03.mealmanager.db.repos.RecipeRepo;
import ch.zhaw.it15a_zh.psit3_03.mealmanager.db.repos.UserPlannedRecipesRepo;
import ch.zhaw.it15a_zh.psit3_03.mealmanager.models.Recipe;
import ch.zhaw.it15a_zh.psit3_03.mealmanager.models.UserPlannedRecipe;

public class InnerWeekplanAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int TYPE_HEADER = 0;
private static final int TYPE_ITEM = 1;
private static final int TYPE_FOOTER = 2;
private List<UserPlannedRecipe> userPlannedRecipeList;
private UserPlannedRecipesRepo uprr = new UserPlannedRecipesRepo();
private RecipeRepo recipeRepo = new RecipeRepo();
private Context context;
private int recipeID;

public InnerWeekplanAdapter(List<UserPlannedRecipe> userPlannedRecipeList, Context context) {
this.userPlannedRecipeList = userPlannedRecipeList;
this.context = context;
}


@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_HEADER) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_weeplan_day_header, parent, false);
return new WeekplanHeaderViewHolder(v);
} else if (viewType == TYPE_FOOTER) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_weekplan_day_footer, parent, false);
return new WeekplanFooterViewHolder(v);
} else if (viewType == TYPE_ITEM) {
View v =
LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_weekplan_day_planned_recipe, parent, false);
return new WeekplanItemViewHolder(v);
}
return null;
}

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


if (holder instanceof WeekplanHeaderViewHolder) {
WeekplanHeaderViewHolder weekplanHeaderViewHolder = (WeekplanHeaderViewHolder) holder;
//TODO Set header fields with get repo information

recipeID = userPlannedRecipeList.get(position).getPlannedRecipeID();
weekplanHeaderViewHolder.textview_date_of_weekplan_row
.setText(userPlannedRecipeList.get(position).getDatePlanned().toString());

} else if (holder instanceof WeekplanItemViewHolder) {
WeekplanItemViewHolder weekplanItemViewHolder = (WeekplanItemViewHolder) holder;
Recipe recipe = new RecipeRepo().getRecipe(userPlannedRecipeList.get(position - 1).getPlannedRecipeID());

//Sets Recipe Name
weekplanItemViewHolder.textView_recipe_name.setText(recipe.getName());
//Sets Image Thumbnail
String imageID = recipe.getImage();
imageID = imageID.substring(0, imageID.lastIndexOf("."));
Uri uri = Uri.parse("android.resource://" + context.getPackageName() + "/drawable/" + imageID);
Picasso.with(context).load(uri).error(R.drawable.placeholder).placeholder(R.drawable.placeholder)
.into(weekplanItemViewHolder.imageView_thumbnail_recipe_image);
//Sets Short Recipe Description
weekplanItemViewHolder.textView_short_recipe_description.setText(recipe.getDescription());
//Sets Cooking Time
weekplanItemViewHolder.textView_cookingTime.setText(String.valueOf(recipe.getCookingTime()));
//TODO implement RemoveRecipeFromPlanning-Button functionality

} else {
WeekplanFooterViewHolder weekplanFooterViewHolder = (WeekplanFooterViewHolder) holder;
weekplanFooterViewHolder.button_plan_recipes_for_this_day.setText("Add Recipes to this day");
//TODO implement AddRecipesToThisDay-Button functionality
}
}

@Override
public int getItemCount() {
return userPlannedRecipeList.size() + 2;
}

@Override
public int getItemViewType(int position) {
if (isPositionHeader(position)) {
return TYPE_HEADER;
} else if (isPositionFooter(position)) {
return TYPE_FOOTER;
}
return TYPE_ITEM;
}

private boolean isPositionHeader(int position) {
return position == 0;
}

private boolean isPositionFooter(int position) {
return position == userPlannedRecipeList.size() + 1;
}


/*BEGIN VIEWHOLDERS*/
public class WeekplanHeaderViewHolder extends RecyclerView.ViewHolder {
public TextView textview_date_of_weekplan_row;

public WeekplanHeaderViewHolder(View view) {
super(view);
this.textview_date_of_weekplan_row = (TextView) itemView.findViewById(R.id.textview_date_of_weekplan_row);
}
}

public class WeekplanItemViewHolder extends RecyclerView.ViewHolder {
public ImageView imageView_thumbnail_recipe_image;
public TextView textView_recipe_name;
public TextView textView_short_recipe_description;
public TextView textView_cookingTime;
public ImageButton imageButton_remove_recipe_from_planning;

public WeekplanItemViewHolder(View view) {
super(view);
this.imageView_thumbnail_recipe_image = (ImageView) view.findViewById(R.id.imageView_thumbnail_recipe_image);
this.textView_recipe_name = (TextView) view.findViewById(R.id.textView_recipe_name);
this.textView_short_recipe_description = (TextView) view.findViewById(R.id.textView_short_recipe_description);
this.textView_cookingTime = (TextView) view.findViewById(R.id.cookingTime);
//this.imageButton_remove_recipe_from_planning =
// (ImageButton) view.findViewById(R.id.imageButton_remove_recipe_from_planning);
//Set Button functionality for removing a recipe from a recyclerview
ImageButton button = (ImageButton) view.findViewById(R.id.imageButton_remove_recipe_from_planning);
button.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context, "Item Removed", Toast.LENGTH_SHORT).show();
}
});
}
}

public class WeekplanFooterViewHolder extends RecyclerView.ViewHolder {
public Button button_plan_recipes_for_this_day;

public WeekplanFooterViewHolder(View view) {
super(view);
this.button_plan_recipes_for_this_day = (Button) view.findViewById(R.id.button_plan_recipes_for_this_day);
}
}
/*END VIEWHOLDERS*/

}


Outer RecyclerView Adapter

import android.content.Context;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import java.util.List;

import ch.zhaw.it15a_zh.psit3_03.mealmanager.R;
import ch.zhaw.it15a_zh.psit3_03.mealmanager.db.repos.UserPlannedRecipesRepo;
import ch.zhaw.it15a_zh.psit3_03.mealmanager.models.UserPlannedRecipe;

public class OuterWeekplanAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static Context context;
private static OuterWeekplanAdapter outerWeekplanAdapter;
private List<String> distinctListOfPlannedDates;
private List<UserPlannedRecipe> userPlannedRecipeList;
private UserPlannedRecipesRepo userPlannedRecipesRepo = new UserPlannedRecipesRepo();
private RecyclerView innerRecyclerView;

public OuterWeekplanAdapter(Context applicationContext, List<String> distinctListOfPlannedDates) {
context = applicationContext;
this.distinctListOfPlannedDates = distinctListOfPlannedDates;

}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_weekplan_cardview, parent, false);
return new OuterWeekplanViewHolder(v);
}


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


CRASH OCCURES HERE APPARENTLY:

innerRecyclerView = (RecyclerView) innerRecyclerView.findViewById(R.id.activity_weekplan_inner_recyclerview);
userPlannedRecipeList =
userPlannedRecipesRepo.getUserPlannedRecipeFromSpecificDate(distinctListOfPlannedDates.get(position));
InnerWeekplanAdapter innerWeekplanAdapter = new InnerWeekplanAdapter(userPlannedRecipeList, context);
RecyclerView.LayoutManager manager = new LinearLayoutManager(context);
innerRecyclerView.setLayoutManager(manager);
innerRecyclerView.setItemAnimator(new DefaultItemAnimator());
innerRecyclerView.setAdapter(innerWeekplanAdapter);

}

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

public class OuterWeekplanViewHolder extends RecyclerView.ViewHolder {
public OuterWeekplanViewHolder(View itemView) {
super(itemView);
}
}
}


"Main" Activity Layout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".activities.WeekPlanActivity">

<include
layout="@layout/toolbar_weekplan_overview"
android:id="@+id/toolbar_weekplan_overview"/>

<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/activity_weekplan_outer_recyclerview"
android:layout_below="@id/toolbar_weekplan_overview"
/>

</RelativeLayout>


CardView Layout:



<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/activity_weekplan_inner_recyclerview"
/>

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


Crash Message:

--------- beginning of crash
11-11 15:52:07.691 6350-6350/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: ch.zhaw.it15a_zh.psit3_03.mealmanager, PID: 6350
java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.support.v7.widget.RecyclerView.findViewById(int)' on a null object reference
at ch.zhaw.it15a_zh.psit3_03.mealmanager.adapters.OuterWeekplanAdapter.onBindViewHolder(OuterWeekplanAdapter.java:41)
at android.support.v7.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:5825)
at android.support.v7.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:5858)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5094)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4970)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2029)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1414)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1377)
at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:578)
at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3315)
at android.support.v7.widget.RecyclerView.onMeasure(RecyclerView.java:2843)
at android.view.View.measure(View.java:18850)
at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:716)
at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:462)
at android.view.View.measure(View.java:18850)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5963)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:135)
at android.view.View.measure(View.java:18850)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5963)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
at android.view.View.measure(View.java:18850)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5963)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.view.View.measure(View.java:18850)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5963)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
at android.view.View.measure(View.java:18850)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5963)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at com.android.internal.policy.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2672)
at android.view.View.measure(View.java:18850)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2102)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1218)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1454)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1109)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6046)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
at android.view.Choreographer.doCallbacks(Choreographer.java:670)
at android.view.Choreographer.doFrame(Choreographer.java:606)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:152)
at android.app.ActivityThread.main(ActivityThread.java:5507)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

Answer

In your OuterWeekplanViewHolder of Outer RecyclerView Adapter
add this

innerRecyclerView = (RecyclerView)itemView.findViewById(R.id.R.id.activity_weekplan_inner_recyclerview);

then use it in your OnBindViewHolder like this

holder.innerRecyclerView.setLayoutManager(manager);
holder.innerRecyclerView.setAdapter(adapter);