androidandroid-fragmentsnullpointerexceptionpagerslidingtabstrip

App crashes when switching between Sliding Tabs by clicking the tabs (not swiping)


So I'm using PagerSlidingTabStrip. I implemented it just like it was suggested in the tutorial and followed the sample/demo-app code.

I have 3 tabs: Calculator | Percentage | History

All 3 extend Fragment. I can swipe between these tabs no problem. But I get a NullPointerException is when I'm on the Calculator tab trying to click the History tab. Here's the error I'm getting:

java.lang.NullPointerException
        at sleeping_vityaz.onerm.tabsswipe.HistoryFragment.loadScreen(HistoryFragment.java:69)
        at sleeping_vityaz.onerm.tabsswipe.HistoryFragment.setUserVisibleHint(HistoryFragment.java:57)
        at android.support.v4.app.FragmentPagerAdapter.setPrimaryItem(FragmentPagerAdapter.java:130)
        at android.support.v4.view.ViewPager.populate(ViewPager.java:1071)
        at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:555)
        at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:514)
        at android.support.v4.view.ViewPager.setCurrentItem(ViewPager.java:495)
        at com.astuetz.PagerSlidingTabStrip$2.onClick(PagerSlidingTabStrip.java:299)
        at android.view.View.performClick(View.java:4438)
        at android.view.View$PerformClick.run(View.java:18422)
        at android.os.Handler.handleCallback(Handler.java:733)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:136)
        at android.app.ActivityThread.main(ActivityThread.java:5001)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:515)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
        at dalvik.system.NativeStart.main(Native Method)

Here is my HistoryFragment code:

public class HistoryFragment extends Fragment {

    public RecordArrayAdapter adapter;
    ArraySwipeAdapterSample mAdapter;
    View rootView;
    DBTools dbTools = null;

    @Override
    public View onCreateView(LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {

        rootView = inflater.inflate(R.layout.history_layout, container, false);
        loadScreen();

        return rootView;
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);

        if (isVisibleToUser) {
            loadScreen();
        } else {
            Log.d("MyFragment", "Fragment is not visible.");
        }
    }

    private void loadScreen() {
        dbTools = DBTools.getInstance(this.getActivity());
        final List<RecordObject> recordsList = dbTools.getAllRecords();

        if (recordsList.size() != 0) {
            ListView listView = (ListView) rootView.findViewById(R.id.records_list);
            mAdapter = new ArraySwipeAdapterSample<String>(getActivity(), R.layout.record_entry, R.id.key_id, recordsList);

            listView.setAdapter(mAdapter);

            mAdapter.setMode(SwipeItemMangerImpl.Mode.Single);
            SwipeLayout swipeLayout = (SwipeLayout) getActivity().findViewById(R.id.swipe);

            /*adapter = new RecordArrayAdapter(this.getActivity(), recordsList);
            listView.setAdapter(adapter);*/
        }
    }
}

history_layout.xml

<ListView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/records_list"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_weight="1"></ListView>

record_entry.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="80dp">

    <com.daimajia.swipe.SwipeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/swipe"
        android:layout_width="match_parent"
        android:layout_height="80dp">
        <!-- Bottom View Start-->
        <LinearLayout
            android:id="@+id/bottom_wrapper"
            android:layout_width="80dp"
            android:layout_height="match_parent"
            android:background="#66ddff00"
            android:weightSum="1">

            <ImageView
                android:id="@+id/img_trash"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@color/accent"
                android:paddingLeft="25dp"
                android:paddingRight="25dp"
                android:src="@drawable/ic_action_delete" />

            <!--What you want to show-->
        </LinearLayout>
        <!-- Bottom View End-->

        <!-- Surface View Start -->
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#ffffff"
            android:padding="10dp">
            <!--What you want to show in SurfaceView-->

            <TextView
                android:id="@+id/key_id"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:visibility="gone" />



            <TextView
                android:id="@+id/onerm"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:layout_weight="2.2"
                android:gravity="center_vertical"
                android:text="WEIGHT"
                android:textColor="#444444"
                android:textSize="16sp"
                android:layout_marginLeft="4dp" />

            <TableLayout
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_weight="3">

                <TextView
                    android:id="@+id/weight"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:text="WEIGHT"
                    android:textColor="#444444"
                    android:textSize="12sp" />

                <TextView
                    android:id="@+id/reps"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:text="REPS"
                    android:textColor="#444444"
                    android:textSize="12sp" />

            </TableLayout>

            <TextView
                android:id="@+id/date"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical|right"
                android:layout_weight="2"
                android:text="DATE"
                android:textColor="#444444"
                android:textSize="12sp"
                android:gravity="center_vertical|right" />




        </LinearLayout>
        <!-- Surface View End -->
    </com.daimajia.swipe.SwipeLayout>
</LinearLayout>

TabsAdapter.java

public class TabsAdapter extends FragmentPagerAdapter {

final private int NUM_TABS = 3;

public TabsAdapter(FragmentManager fm) {
    super(fm);
}

@Override
public Fragment getItem(int position) {
    switch (position) {
        case 0: return new CalculatorFragment();
        case 1: return new PercentageFragment();
        case 2: return new HistoryFragment();
    }
    return null;
}

@Override
public int getCount() {
    return NUM_TABS;
}

@Override
public CharSequence getPageTitle (int position) {

    switch (position) {
        case 0: return "Calculator";
        case 1: return "Percentage";
        case 2: return "History";
        default:return null;
    }
}

}

What could be causing this error? This only happens when I try to switch from the Calculator fragment to History fragment by clicking the tabs (and not swiping) AND when the user has already saved something to the database (recordsList.size() != 0). If recordsList is empty, there's no error.

Also, HistoryFragment.java:68 is the following line

ListView listView = (ListView) rootView.findViewById(R.id.records_list);

Solution

  • I was able to solve this by myself :) So what happened was that setUserVisibleHint method was calling loadScreen because the screen was visible to the user. The problem with that was that History fragment's onCreateView was never called in the first place! So all I had to do was to check for rootView!=null in my loadScreen method. Duh! This fixed everything.

    This is what I had before

    if (recordsList.size() != 0) {
    

    and what I have now

    if (recordsList.size() != 0 && rootView!=null) {