I have a fragment that is loaded on a Tab and then loads a RecyclerView and sets an adapter with two ViewHolder's. The data on the screen is displayed on the screen through CardViews.
One card for the top and multiple cards for the rest of the data. A representation of it is as follows:
My first and biggest problem is that it loads fine as you can see on the picture above, but when I try to scroll I get the error:
Application has stopped unexpectedly: Thread[main,5,main] failed: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.support.v7.widget.RecyclerView$LayoutManager.canScrollHorizontally()' on a null object reference at android.support.v7.widget.RecyclerView.computeHorizontalScrollOffset(RecyclerView.java:1548) at android.view.View.canScrollHorizontally(View.java:12827) at android.support.v4.view.ViewCompatICS.canScrollHorizontally(ViewCompatICS.java:31) at android.support.v4.view.ViewCompat$ICSViewCompatImpl.canScrollHorizontally(ViewCompat.java:1249) at android.support.v4.view.ViewCompat.canScrollHorizontally(ViewCompat.java:1684) at android.support.v4.view.ViewPager.canScroll(ViewPager.java:2561) at android.support.v4.view.ViewPager.canScroll(ViewPager.java:2552) at android.support.v4.view.ViewPager.canScroll(ViewPager.java:2552) at android.support.v4.view.ViewPager.onInterceptTouchEvent(ViewPager.java:1923) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1961) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2406) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2107) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2406) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2107) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2406) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2107) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2406) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2107) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2406) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2107) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2406) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2107) at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2625) at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1770) at android.app.Activity.dispatchTouchEvent(Activity.java:2742) at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:60) at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:60) at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2586) at android.view.View.dispatchPointerEvent(View.java:8675) at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4129) at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:3995) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3550) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3603) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3569) at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3686) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3577) at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3743) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3550) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3603) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3569) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3577) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3550) at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:5813) at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:5787) at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:5758) at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:5903) at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185) at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method) at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:176) at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:5874) at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:5926) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767) at android.view.Choreographer.doCallbacks(Choreographer.java:580) at android.view.Choreographer.doFrame(Choreographer.java:548) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:135) at android.app.ActivityThread.main(ActivityThread.java:5294) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699)
The second thing I wanted to ask is whether you think this is the right way to implement this. Should i be using multiple view holders inside a RecyclerView? Will that affect performance?
My code is as follows:
HomeFragment.java
public class HomeFragment extends Fragment{
private List<Favourite> favourites;
private RecyclerView rv;
FavouriteAdapter fa;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.home_fragment, container, false);
// Get recycler view reference
rv = (RecyclerView) view.findViewById(R.id.favourite_card_rv);
// Set layout manager
rv.setLayoutManager(new LinearLayoutManager(getActivity()));
// some data
// This only returns a list of objects with some data
initializeData();
// Create adapter
fa = new FavouriteAdapter(getActivity(), favourites);
// Set adapter
rv.setAdapter(fa);
// return
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
}
FavouriteAdapter.java
public class FavouriteAdapter extends RecyclerView.Adapter<FavouriteAdapter.MainViewHolder> {
List<Favourite> favourites;
Context context;
final int VIEW_TYPE_TOP = 0;
final int VIEW_TYPE_FAVOURITES = 1;
// Constructor
public FavouriteAdapter(Context context, List<Favourite> favourites) {
if (favourites == null) {
throw new IllegalArgumentException(
"favourites must not be null");
}
this.favourites = favourites;
this.context = context;
}
static class MainViewHolder extends RecyclerView.ViewHolder {
CardView cv;
TextView videoName;
TextView videoUrl;
ImageView videoImage;
public MainViewHolder(View v) {
super(v);
cv = (CardView)itemView.findViewById(R.id.cv);
videoName = (TextView)itemView.findViewById(R.id.video_name);
videoUrl = (TextView)itemView.findViewById(R.id.video_url);
videoImage = (ImageView)itemView.findViewById(R.id.video_photo);
}
}
static class TopFavouriteViewHolder extends MainViewHolder{
TopFavouriteViewHolder(View itemView) {
super(itemView);
}
}
static class FavouriteViewHolder extends MainViewHolder {
FavouriteViewHolder(View itemView) {
super(itemView);
}
}
@Override
public int getItemCount() {
return favourites.size();
}
@Override
public int getItemViewType(int position) {
return (position == 0? VIEW_TYPE_TOP : VIEW_TYPE_FAVOURITES);
}
@Override
public MainViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View view;
switch(viewType){
case 0:
view = LayoutInflater
.from(viewGroup.getContext())
.inflate(R.layout.top_card, viewGroup, false);
return new TopFavouriteViewHolder(view);
case 1:
view = LayoutInflater
.from(viewGroup.getContext())
.inflate(R.layout.favourite_card, viewGroup, false);
return new FavouriteViewHolder(view);
}
return null;
}
@Override
public void onBindViewHolder(MainViewHolder holder, int i) {
holder.videoName.setText(favourites.get(i).name);
holder.videoUrl.setText(favourites.get(i).url);
Picasso.with(this.context).load(favourites.get(i).image).into(holder.videoImage);
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
}
I've looked at many threads here and tried lots of different combinations, but can't seem to be able to get past this problem.
Any help much appreciated.
Thanks