java - 使用 fragmentstatepageradapter 的 nullpointerexception

标签 java android android-fragments nullpointerexception fragmentstatepageradapter

我正在制作的应用程序出现问题,一切似乎都正常,直到我开始收到一个错误,似乎是无中生有,我不相信我从它工作时改变了任何东西,但每次我打开 Activity 它给我一个 NullPointerException,这是它的 logcat。

09-13 18:29:54.951: E/AndroidRuntime(4407): FATAL EXCEPTION: main
09-13 18:29:54.951: E/AndroidRuntime(4407): Process: renseew.knowyourtime, PID: 4407
09-13 18:29:54.951: E/AndroidRuntime(4407): java.lang.NullPointerException
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.support.v13.app.FragmentCompatICS.setMenuVisibility(FragmentCompatICS.java:23)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.support.v13.app.FragmentCompat$ICSFragmentCompatImpl.setMenuVisibility(FragmentCompat.java:41)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.support.v13.app.FragmentCompat.setMenuVisibility(FragmentCompat.java:68)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.support.v13.app.FragmentStatePagerAdapter.instantiateItem(FragmentStatePagerAdapter.java:120)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.support.v4.view.ViewPager.addNewItem(ViewPager.java:837)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.support.v4.view.ViewPager.populate(ViewPager.java:987)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.support.v4.view.ViewPager.populate(ViewPager.java:919)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1441)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.View.measure(View.java:16497)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.support.v4.widget.DrawerLayout.onMeasure(DrawerLayout.java:762)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.View.measure(View.java:16497)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.View.measure(View.java:16497)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at com.android.internal.widget.ActionBarOverlayLayout.onMeasure(ActionBarOverlayLayout.java:327)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.View.measure(View.java:16497)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5125)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2291)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.View.measure(View.java:16497)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:1916)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1113)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1295)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1000)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5670)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.Choreographer.doCallbacks(Choreographer.java:574)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.Choreographer.doFrame(Choreographer.java:544)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.os.Handler.handleCallback(Handler.java:733)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.os.Handler.dispatchMessage(Handler.java:95)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.os.Looper.loop(Looper.java:136)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at android.app.ActivityThread.main(ActivityThread.java:5017)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at java.lang.reflect.Method.invokeNative(Native Method)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at java.lang.reflect.Method.invoke(Method.java:515)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
09-13 18:29:54.951: E/AndroidRuntime(4407):     at dalvik.system.NativeStart.main(Native Method)

该 Activity 使用 FragmentStatePagerAdapter 动态地将选项卡从 fragment 添加到 Activity , 我还尝试将 if(position < companies.size() -1) 更改为 if(position < companies.size()) 没有变化(第一个在我开始收到错误之前有效)这是 Activity 代码。

public class UserDetails extends BaseActivity implements ActionBar.TabListener {

    CompanyPagerAdapter companyPagerAdapter;
    ViewPager viewPager;
    Cursor cursor;

    SettingsDBAdapter settingsDBAdapter;
    String companyName;
    private List<String> companies = new ArrayList<String>();
    ActionBar ab;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user_details);
        updateActionBarNavigation();
        initialize();
        setupTabs();
        getCompanies();
        getTabs();
    }

    private void initialize() {
        if(ab != null)
            ab.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        viewPager = (ViewPager) findViewById(R.id.UDviewpager);

        ContentResolver settingsContent = this.getContentResolver();
        cursor = settingsContent.query(KnowYourTimeContentProvider.CONTENT_URI_SETTINGS, null, null, null, null);
        settingsDBAdapter = new SettingsDBAdapter(getApplicationContext());

        if (cursor.getCount() == 0) {
            settingsDBAdapter.settingsDBOpen();
            settingsDBAdapter.setDefaultSettings();
        }
    }

    private void setupTabs() {
        companyPagerAdapter = new CompanyPagerAdapter(getFragmentManager());

        viewPager.setAdapter(companyPagerAdapter);
        viewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
                    @Override
                    public void onPageSelected(int position) {
                        if (ab != null) {
                            ab.setSelectedNavigationItem(position);
                        }
                    }
                });
    }

    private void getTabs() {
        for (int i = 0; i < companyPagerAdapter.getCount(); i++) {
            if (ab != null) {
                ab.addTab(ab.newTab()
                        .setText(companyPagerAdapter.getPageTitle(i))
                        .setTabListener(this));
            }
        }
    }

    private void getCompanies() {
        cursor = settingsDBAdapter.getCompanies();
        if (companies.size() != 0) {
            for (int i = 0; i < companies.size(); i++) {
                companyName = companies.get(i);
                companies.add(companyName);
            }
        } else if (cursor.getCount() != 0) {
            while (cursor.moveToNext()) {
                companyName = cursor.getString(cursor.getColumnIndex("company"));
                companies.add(companyName);
            }
        } else {
            companyName = getString(R.string.company);
            companies.add(companyName);
        }
        companyPagerAdapter.notifyDataSetChanged();
    }

    @Override
    protected void onNavDrawerStateChanged(boolean isOpen, boolean isAnimating) {
        super.onNavDrawerStateChanged(isOpen, isAnimating);
        updateActionBarNavigation();
    }

    @Override
    protected void onActionBarAutoShowOrHide(boolean shown) {
        super.onActionBarAutoShowOrHide(shown);
    }

    private void updateActionBarNavigation() {
        boolean show = !isNavDrawerOpen();

        ab = getActionBar();
        if (show && ab != null) {
            ab.setDisplayShowCustomEnabled(true);
            ab.setDisplayShowTitleEnabled(true);
            ab.setDisplayUseLogoEnabled(false);
            ab.setTitle(getString(R.string.title_user_details));
        } else if (ab != null) {
            ab.setDisplayShowCustomEnabled(false);
            ab.setDisplayShowTitleEnabled(false);
            ab.setDisplayUseLogoEnabled(true);
        }
    }

    @Override
    protected int getSelfNavDrawerItem() {
        return NAVDRAWER_ITEM_USERDETAILS;
    }

    @Override
    public void onTabSelected(ActionBar.Tab tab,
                              FragmentTransaction fragmentTransaction) {
        viewPager.setCurrentItem(tab.getPosition());

        companies.get(tab.getPosition());
    }

    @Override
    public void onTabUnselected(ActionBar.Tab tab,
                                FragmentTransaction fragmentTransaction) {
    }

    @Override
    public void onTabReselected(ActionBar.Tab tab,
                                FragmentTransaction fragmentTransaction) {
    }

    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.usersettings_menu, menu);
        return true;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        menu.clear();
        menu.add(Menu.NONE, R.id.addCompany, Menu.NONE, getString(R.string.add) + " " + getString(R.string.company));
        menu.add(Menu.NONE, R.id.removeCompany, Menu.NONE, getString(R.string.subtract) + " " + getString(R.string.company));
        return super.onPrepareOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem menuItem) {
        switch (menuItem.getItemId()) {
            case R.id.addCompany:
                companies.clear();
                companyName = getString(R.string.company);
                companies.add(companyName);
                companyPagerAdapter.notifyDataSetChanged();
                getTabs();
                return true;
            case R.id.removeCompany:
                return true;
            default:
                return super.onOptionsItemSelected(menuItem);
        }
    }

    public class CompanyPagerAdapter extends FragmentStatePagerAdapter {

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

        @Override
        public Fragment getItem(int position) {
            while (position < companies.size() - 1) {
                if (position < companies.size() - 1) {
                    position++;
                    return FragmentUserDetails.newInstance(companies.get(position));
                }
            }
            return null;
        }

        @Override
        public int getCount() {
            return companies.size();
        }

        @Override
        public CharSequence getPageTitle(int position) {
            while (position < companies.size() - 1) {
                if (position < companies.size() - 1) {
                    position++;
                    return companies.get(position);
                }
            }
            return "";
        }
    }
}

这里是 Activity 打开的 fragment 的代码。

public class FragmentUserDetails extends Fragment implements AdapterView.OnItemClickListener, View.OnClickListener {

    private BaseAdapter listAdapter;
    private Cursor settingsCursor, companyCursor;

    private String payrate, payperiod, weekstart, allowances, maritalstatus;
    private String companyname;
    private Switch cbMaritalStatus;
    public EditText etCompanyName, etPayrate;
    private Spinner sPayPeriod, sPeriodStart, sAllowances;
    SettingsDBAdapter settingsDBAdapter;

    static FragmentUserDetails newInstance(String title) {
        FragmentUserDetails fragmentUserDetails = new FragmentUserDetails();
        Bundle args = new Bundle();
        args.putString("title", title);
        fragmentUserDetails.setArguments(args);
        return fragmentUserDetails;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_user_details, container, false);
        initialization(view);
        return view;
    }

    private void initialization(View view) {
        etCompanyName = (EditText) view.findViewById(R.id.UDedittextCompany);
        etPayrate = (EditText) view.findViewById(R.id.UDedittextPayrate);
        sPayPeriod = (Spinner) view.findViewById(R.id.UDspinnerPayPeriod);
        sPeriodStart = (Spinner) view.findViewById(R.id.UDspinnerPeriodStart);
        sAllowances = (Spinner) view.findViewById(R.id.UDspinnerAllowances);
        cbMaritalStatus = (Switch) view.findViewById(R.id.UDswitchMaritalStatus);
        Button save = (Button) view.findViewById(R.id.UDbuttonSaveSettings);

        save.setOnClickListener(this);

        ContentResolver settingsContent = getActivity().getContentResolver();
        settingsCursor = settingsContent.query(KnowYourTimeContentProvider.CONTENT_URI_SETTINGS, null, null, null, null);
        settingsDBAdapter = new SettingsDBAdapter(getActivity().getApplicationContext());

        companyname = getArguments().getString("title");

        if (settingsCursor.getCount() != 0) {
            while (settingsCursor.moveToNext()) {
                companyCursor = settingsDBAdapter.fetchCompanyInfo(companyname);
            }

            if (companyCursor.getCount() != 0) {
                while (companyCursor.moveToNext()) {
                    payrate = companyCursor.getString(companyCursor.getColumnIndex("payrate"));
                    payperiod = companyCursor.getString(companyCursor.getColumnIndex("payperiod"));
                    weekstart = companyCursor.getString(companyCursor.getColumnIndex("weekstart"));
                    allowances = companyCursor.getString(companyCursor.getColumnIndex("allowances"));
                    maritalstatus = companyCursor.getString(companyCursor.getColumnIndex("maritalstatus"));
                }
            } else {
                payrate = "";
                payperiod = getString(R.string.weekly);
                weekstart = getString(R.string.sunday);
                allowances = "0";
                maritalstatus = getString(R.string.no);
            }
        } else {
            companyname = getString(R.string.company);
        }

        etCompanyName.setText(companyname);
        etPayrate.setText(payrate);
        sPayPeriod.setSelection(getIndex(sPayPeriod, payperiod));
        sPeriodStart.setSelection(getIndex(sPeriodStart, weekstart));
        sAllowances.setSelection(getIndex(sAllowances, allowances));

        if (maritalstatus.equals(getString(R.string.yes))) {
            cbMaritalStatus.setChecked(true);
        } else {
            cbMaritalStatus.setChecked(false);
        }
    } 
}

抱歉放了这么多代码,我只是不确定是什么导致了这个问题。在此先感谢您的帮助

更新: 所以错误似乎确实来自 getItem() 使用调试器。它运行一次就好了(这是有道理的,因为最初有 1 行)但是第二次是它导致崩溃的时候。我还将其中的代码更改为此

public Fragment getItem(int position) {
    FragmentUserDetails fragment = null;
        if (position < companies.size() - 1) {
            fragment = FragmentUserDetails.newInstance(companies.get(position));
        }
    return fragment;
}

按照建议使其更简单。仍然得到同样的错误。再次感谢您的帮助

最佳答案

您对 getItem() 的实现看起来非常可疑。这可能与您当前的错误有关,也可能无关。让我们分析一下您当前的代码:

    public Fragment getItem(int position) {
        while (position < companies.size() - 1) {
            if (position < companies.size() - 1) {
                position++;
                return FragmentUserDetails.newInstance(companies.get(position));
            }
        }
        return null;
    }

为了继续这个分析,我们需要定义先决条件:

  1. companies 包含 5 个 String。确切的值无关紧要。

  2. position 从 0 开始,值为 2

在这种特殊情况下,whileif 条件的计算结果都是 true,因此 position 递增我们立即返回 newInstance() 的值。

这表明了一些非常重要的事情:只要 while 条件为 trueif 条件也为 true ,我们将立即返回一个值。这完全不需要 while 循环。

现在我们看到这个实现是不正确的,让我们备份并检查我们想要完成的事情。主要思想是我们要为索引 位置 处的“公司”返回一个 Fragment。简单的实现非常简单:

    public Fragment getItem(int position) {
        return FragmentUserDetails.newInstance(companies.get(position));
    }

理论上,position永远不应该在范围之外,但是如果你想保险起见,可以添加一个if语句来进行错误检查:

    public Fragment getItem(int position) {
        if (0 <= position && position < companies.size()) {
            return FragmentUserDetails.newInstance(companies.get(position));
        }
    }

现在,如果您仍然没有得到预期的行为,则错误出在其他地方,我们将需要分析您代码的其他部分。

关于java - 使用 fragmentstatepageradapter 的 nullpointerexception,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25828860/

相关文章:

java - 该方法没有正确检查该值

java - 无法在 Android 中显示来自 Firebase 实时数据库的随机数据

java - 将 JList 保存到 Txt 文件中

java - 在类(而不是 Activity )之间传递数据会导致空指针异常

java - 从没有附加变量的 fragment 获取数据

android - 为什么要使用 fragment ?

android - Kotlin-MainActivity的调用 fragment 方法

java - if-else 条件 : AND evaluation mystery

java - Android 外设 BluetoothGattServerCallback onServiceAdded() 没有被调用

android - 在半透明 Activity 中显示警报对话框