通过单击选项卡(而不是滑动)在滑动选项卡之间切换时应用程序崩溃

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

所以我正在使用 PagerSlidingTabStrip。我按照教程中的建议实现了它,并遵循了 sample/demo-app 代码。

我有 3 个选项卡:计算器 |百分比 |历史

所有 3 个扩展 Fragment。我可以在这些选项卡之间滑动没问题。但是当我在“计算器”选项卡上尝试单击“历史记录”选项卡时,出现 NullPointerException。这是我收到的错误:

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.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)

这是我的 HistoryFragment 代码:

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 扩展了 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;
    }
}

}

什么可能导致此错误?仅当我尝试通过单击选项卡(而不是滑动)AND 从计算器片段切换到历史片段时,当用户已经将某些内容保存到数据库时(recordsList.size() != 0).如果 recordsList 为空,则没有错误。

此外,HistoryFragment.java:68 是下面这行

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

我能够自己解决这个问题 :) 所以发生的事情是 setUserVisibleHint 方法正在调用 loadScreen 因为屏幕对用户可见。问题是历史片段的 onCreateView 一开始就没有被调用过!所以我所要做的就是在我的 loadScreen 方法中检查 rootView!=null 。呸!这解决了所有问题。

这是我之前的

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

以及我现在拥有的

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

在你崩溃的片段中设置:

if (activity != null && isAdded) {
      // perform your task
}