I have expandable cardview that I want to expand the first cardview at position 0 after 15 sec collapse position 0 expand position 1 after 15 seconds again I collapse position 1 and expand position 2. I have managed to expand position 0 and expand position after 15 sec , now the next round of 15 second it crashes with error java.lang.NullPointerException: Attempt to read from field 'android.view.View android.support.v7.widget.RecyclerView$ViewHolder.itemView' on a null object reference

Here is my Adapter

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



private Context context;

private List<com.aw.governor.model.summary.ResponseDatum> mList = new ArrayList<>();
public static  ViewHolder viewHolder;

public SummeryAdapter(Context context , List<com.aw.governor.model.summary.ResponseDatum> mList){
    this.context = context;
    this.mList = mList;

}

public  class ViewHolder extends RecyclerView.ViewHolder{

    TextView average_header,tVheader,value;
    LinearLayout layout;
    ImageView image;
    FrameLayout frLayout;
   public ExpandableCardView main_profile_card;
    RecyclerView recyclerView;

    public ViewHolder(View itemView) {
        super(itemView);

        average_header =(TextView)itemView.findViewById(R.id.average_header);
        value = (TextView) itemView.findViewById(R.id.value);
        main_profile_card =(ExpandableCardView) itemView.findViewById(R.id.main_profile_card);
        recyclerView = (RecyclerView)itemView.findViewById(R.id.recyclerView);



    }
}


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

    View view = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.item_summary,parent , false);

    ViewHolder vh = new ViewHolder(view);

    return vh;
}

@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
    viewHolder = holder;
    final com.aw.governor.model.summary.ResponseDatum list = mList.get(position);
    holder.main_profile_card.setTitle(list.getLabel());
    holder.value.setText("KES "+String.valueOf(list.getAmount()));
    holder.average_header.setText(list.getAverageLabel()+": "+String.valueOf(roundTwoDecimals(list.getAverage())));
    PerformanceAdapter adapter = new PerformanceAdapter(context, list.getPerformance());
    adapter.notifyDataSetChanged();
    holder.recyclerView.setLayoutManager(new LinearLayoutManager(context));
    holder.recyclerView.setAdapter(adapter);
    holder.recyclerView.setHasFixedSize(false);



}



double roundTwoDecimals(double d)
{
    DecimalFormat twoDForm = new DecimalFormat("#.##");
    return Double.valueOf(twoDForm.format(d));
}

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

Here is my Fragmet where am doing the expanding from and to

  static Handler h = new Handler();
static int delay = 15*1000; //1 second=1000 milisecond, 15*1000=15seconds
static   Runnable runnable;
static int Epxand =0;
static int Collaps =0;


public static void expandCard(int Position){
    Log.i("### expandCard ",String.valueOf(Position));
    ((ExpandableCardView) recyclerView.findViewHolderForAdapterPosition(Position).itemView.findViewById(R.id.main_profile_card)).expand();
}
public static void collapseCard(int Position){
    Log.i("### collapseCard ",String.valueOf(Position));
    ((ExpandableCardView) recyclerView.findViewHolderForAdapterPosition(Position).itemView.findViewById(R.id.main_profile_card)).collapse();
}

on click a button it run this code

 expandCard(Epxand);
        h.postDelayed( runnable = new Runnable() {
            public void run() {
                collapseCard(Collaps);
                Epxand++;
                expandCard(Epxand);
                Collaps++;
                Log.i("###","15sec gone\n");
                h.postDelayed(runnable, (delay+1000));

            }
        }, delay);

Error log

    04-27 11:36:47.769 20504-20504/com.aw.governor I/### expandCard: 0
04-27 11:36:52.772 20504-20504/com.aw.governor I/### collapseCard: 0
04-27 11:36:52.773 20504-20504/com.aw.governor I/### expandCard: 1
04-27 11:36:52.931 20504-20504/com.aw.governor I/###: 15sec gone
04-27 11:36:58.936 20504-20504/com.aw.governor I/### collapseCard: 1
04-27 11:36:58.937 20504-20504/com.aw.governor I/### expandCard: 2

    --------- beginning of crash
04-27 11:36:58.937 20504-20504/com.aw.governor E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.aw.governor, PID: 20504
    java.lang.NullPointerException: Attempt to read from field 'android.view.View android.support.v7.widget.RecyclerView$ViewHolder.itemView' on a null object reference
        at com.aw.governor.fragments.Home.expandCard(Home.java:178)
        at com.aw.governor.fragments.Home$3.run(Home.java:165)
        at android.os.Handler.handleCallback(Handler.java:815)
        at android.os.Handler.dispatchMessage(Handler.java:104)
        at android.os.Looper.loop(Looper.java:207)
        at android.app.ActivityThread.main(ActivityThread.java:5765)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679)

enter image description here

This is my Fragment Class

    public class Home extends Fragment{


    public Home() {
        // Required empty public constructor
    }
   public static RecyclerView recyclerView;

    public static   Boolean ShowingEarnings = true;
    public  static Context context ;
   public static EarningsResponse earningsResponse;
   public static SummaryResponse summaryResponse;
  static ScrollView scrollView;

   public static EarningsAdapter adapter;


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View rootView =inflater.inflate(R.layout.fragment_home, container, false);
        recyclerView = (RecyclerView)rootView.findViewById(R.id.recyclerView);

        scrollView =(ScrollView) rootView.findViewById(R.id.scrollView);

        context  = getActivity();

        ExecutiveAppDashboard(getActivity());


        return rootView;
    }

    public static void ExecutiveAppDashboard(final Context context){
        ShowingEarnings = true;
        MainActivity.back_arrow.setVisibility(View.GONE);
        Api.getVolley(context,  Api.ExecutiveAppDashboard, "", new Api.VolleyCallback() {
            @Override
            public void onSuccess(String result) {
                earningsResponse = Api.mGson.fromJson(result,EarningsResponse.class);
                if(earningsResponse.getStatusCode()==200){

                    adapter = new EarningsAdapter(context, earningsResponse.getResponseData());
                    adapter.notifyDataSetChanged();

                    recyclerView.setLayoutManager(new LinearLayoutManager(context));
                    recyclerView.setAdapter(adapter);
                    recyclerView.setHasFixedSize(false);

                }else {

                }
            }
        });
    }
    public static void ExecutiveAppTransactionSummary(final Context context){
        ShowingEarnings = false;
        Api.getVolley(context,  Api.ExecutiveAppTransactionSummary, "", new Api.VolleyCallback() {
            @Override
            public void onSuccess(String result) {
                 summaryResponse = Api.mGson.fromJson(result,SummaryResponse.class);
                if(summaryResponse.getStatusCode()==200){

                    SummeryAdapter adapter = new SummeryAdapter(context, summaryResponse.getResponseData());
                    adapter.notifyDataSetChanged();

                    recyclerView.setLayoutManager(new LinearLayoutManager(context));
                    recyclerView.setAdapter(adapter);
                    recyclerView.setHasFixedSize(false);

                }else {

                }
            }
        });
    }

    static double roundTwoDecimals(double d)
    {
        DecimalFormat twoDForm = new DecimalFormat("#.##");
        return Double.valueOf(twoDForm.format(d));
    }


    public static void voiceReport(){
        if(ShowingEarnings){
            MainActivity.speak(MainActivity.getGreetings()+" your excellency Governor Sonko. I am your personal assistant Samolita");

            for (ResponseDatum responseDatum:  earningsResponse.getResponseData()) {
                MainActivity.speak(responseDatum.getHeader()+" is "+responseDatum.getValue()+" Kenya shillings."+ "Average per hour is "+roundTwoDecimals(responseDatum.getAverage()));
            }

            MainActivity.speak("That's all I have for now."+ MainActivity.getSeeOffMessage());
           //MainActivity.switchOffMic(MainActivity.context);

        }else {

            MainActivity.speak("Your excellency.");

            for (com.aw.governor.model.summary.ResponseDatum responseDatum:  summaryResponse.getResponseData()) {
                MainActivity.speak(responseDatum.getLabel()+" is "+responseDatum.getAmount()+" Kenya shillings."+ "Average per hour is "+roundTwoDecimals(responseDatum.getAverage())+". ");

                for (Performance performance: responseDatum.getPerformance()) {
                    MainActivity.speak(performance.getPerformanceLabel()+" "+String.valueOf(performance.getPerformanceData().size()));

                    for (PerformanceDatum performanceDatum: performance.getPerformanceData()) {
                        MainActivity.speak(performanceDatum.getName()+" "+String.valueOf(performanceDatum.getAmount()+" Kenya Shillings")+" contributing "
                                +String.valueOf(roundTwoDecimals(performanceDatum.getPercentage())+"%")+" of "+responseDatum.getLabel());
                    }
                }
            }

            MainActivity.speak("That's all I have for now."+ MainActivity.getSeeOffMessage());

           // MainActivity.switchOffMic(MainActivity.context);


            expandCard(Epxand);
            h.postDelayed( runnable = new Runnable() {
                public void run() {
                    collapseCard(Collaps);
                    Epxand++;
                    expandCard(Epxand);
                    Collaps++;
                    Log.i("###","15sec gone\n");
                    h.postDelayed(runnable, (delay+1000));

                }
            }, delay);

        }
    }

    static Handler h = new Handler();
    static int delay = 15*1000; //1 second=1000 milisecond, 15*1000=15seconds
    static   Runnable runnable;
    static int Epxand =0;
    static int Collaps =0;


    public static void expandCard(int Position){
        Log.i("### expandCard ",String.valueOf(Position));
        ((ExpandableCardView) recyclerView.findViewHolderForAdapterPosition(Position).itemView.findViewById(R.id.main_profile_card)).expand();
    }
    public static void collapseCard(int Position){
        Log.i("### collapseCard ",String.valueOf(Position));
        ((ExpandableCardView) recyclerView.findViewHolderForAdapterPosition(Position).itemView.findViewById(R.id.main_profile_card)).collapse();
    }

}

This is the xml

    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:id="@+id/scrollView"
    android:layout_height="match_parent"
    tools:context="com.aw.governor.fragments.Home">
    <android.support.v7.widget.RecyclerView
        android:visibility="visible"
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

</ScrollView>

1 Answers

0
nitinkumarp On Best Solutions

Recyclerview recycles the views which are not visible. So the next expanding position is probably not recreated when the expand code is executed. That is why the viewHolder is null.

There are certain things you can try out:

  1. Add delay between Collapse and Expand.
  2. Use your LayoutManager to check if expanding position is in view or not and then expand the position.
  3. You can try using NestedScrollView instead of ScrollView and put android:nestedScrollingEnabled="false" in Recyclerview. It might work with your current code but mind you its a bad hack and not good for performance.