从活动调用Fragment方法时的NullPointer

时间:2014-05-24 22:02:42

标签: android android-fragments nullpointerexception

自上周以来,我一直在努力解决这个错误。这是:

public class MainActivity extends FragmentActivity implements ActionBar.TabListener {
    AppSectionsPagerAdapter mAppSectionsPagerAdapter;
    ViewPager mViewPager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mAppSectionsPagerAdapter = new AppSectionsPagerAdapter(getSupportFragmentManager(), getApplicationContext());
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(mAppSectionsPagerAdapter);
        ...
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle item selection
        switch (item.getItemId()) {
        case R.id.refresh:
            mAppSectionsPagerAdapter.onRefresh();
            return true;
        ...
    }


public class AppSectionsPagerAdapter extends FragmentPagerAdapter {
    private ArrayList<Fragment> fragmentList;
    private MainSectionFragment f1, f2;
    private SelectedSectionFragment f3;

    public AppSectionsPagerAdapter(FragmentManager fm, Context c) {
        f3 = new SelectedSectionFragment();
        f2 = new MainSectionFragment();
        f1 = new MainSectionFragment();

        fragmentList = new ArrayList<Fragment>();
        fragmentList.add(f1);
        fragmentList.add(f2);
        fragmentList.add(f3);
        ...
    }

    public void onRefresh(){
        MainSectionFragment fragment = (MainSectionFragment)fragmentList.get(0);
        fragment.fetchList();
    }
    ...
}

public class MainSectionFragment extends Fragment implements CallbackListener {
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        //some initialization
        c = getActivity().getApplicationContext(); // tested and it gets initialized
        System.out.println(""+hashCode());
        ...
    }

    void fetchList() {
        System.out.println(""+hashCode());
        android.support.v4.app.FragmentManager manager = getActivity().getSupportFragmentManager();
        ...
    }
}

description

我从ActivityMain导航,它就死了。当我回来时,列表可以垂直和水平滚动。如果我单击刷新按钮NullPointerException出现。我调试了这个程序。从SettingsActivity返回时会调用OnCreateView(),但当我点击“刷新”按钮时,MainSectionFragment的每个字段都会变为 null

异常前打印的哈希码:

05-25 01:54:37.190: I/System.out(5982): 1091848056 //onCreateView()
05-25 01:54:42.680: I/System.out(5982): 1091574888 //fetchList()

无法理解为什么这些对象会有所不同。

如果我的问题不明确,请告诉我。

更新1

我已经检查过“不要保持活动&#39;开发工具中的选项。我已经确认从SettingsActivity返回后调用了MainActivity onCreate

更新2

转到SettingsActivity 分离片段。从SettingsActivity返回 再次附加片段。

2 个答案:

答案 0 :(得分:3)

修改

尽管最初的答案非常接近正确回答,但我想编辑以便为案例带来一些知识。

Fragment堆栈(在某种观点下)与活动非常相似。因为片段也会被框架自动销毁并重新创建,并通过绕过回调传递的Bundles保存状态(savedInstanceState)。

所以正在发生的事情是,即使正在重新创建活动并调用新的适配器,在向ViewPager提供片段时,适配器首先将findFragmentByTag调用到FragmentManager这样就可以重新创建保存的状态,如果没有,则只调用public Fragment getItem(int position)

因此,您在屏幕上看到的片段不是AppSectionsPagerAdapter构造函数中创建的对象。那些碎片从未使用过。

请记住,尽管乍一看听起来很奇怪,但这是一个非常理想的功能。例如:假设片段上有一个EditText,用户用一些文本填充它。当碎片被破坏时,该值将保存在Bundle上,并且在恢复时,该值仍然存在。

原始回答:

&#34;无法理解为什么这些对象不同。&#34;因为这就是框架的运作方式。片段是可以由框架销毁/重新创建的对象。

99%的可能性是:

  • MainActivity.onCreate.onStart.onResume
  • MainSectionFragment.onCreateView.onResume
  • 然后转到设置:
  • MainSectionFragment.onPause.onDestroyView&lt;&lt;&lt;破坏视图
  • MainActivity.onPause.onStop
  • 从设置中退出时
  • MainActivity.onStart.onResume&lt;&lt;&lt;它没有调用onCreate,它从未被销毁过。
  • 框架会自动重新创建您的片段
  • MainSectionFragment(新实例).onCreateView.onResume
  • 点击refresh按钮
  • MainActivity调用旧的MainSectionFragment。视图已被销毁的MainSectionFragment。

修复代码的最直接(也更清晰)方法是让Fragment处理菜单,只需将其简单地放入片段代码中,然后从活动中删除菜单内容:

onCreate(Bundle savedInstance){
   setHasOptionsMenu(true);
}

onOptionsItemSelected(MenuItem item){
   if(item.getItemId() == R.id.refresh){
      .. do your stuff here
      return true;
   } else return super.refresh(item);
}

如果由于某种原因你没有解释你真的必须处理活动中的菜单还有其他选择:

例如:您可以从活动中发送LocalBroadcast并让片段在onResume / onPause期间注册/取消注册BroadcastReceiver

或另一个好方法:FragmentPagerAdater使用以下方法为FragmentManager创建片段TAG:

private static String makeFragmentName(int viewId, long id) {
   return "android:switcher:" + viewId + ":" + id;
}

然后您可以将其添加到您的活动中并致电:

 (MainSectionFragment)getSupportFragmentManager().
     findFragmentByTag(
         makeFragmentName(R.id.pager, mAppSectionsPagerAdapter.getItemId(0)))
           .fetchList();

答案 1 :(得分:1)

我认为如果您保留实例,它可能会解决问题。

要在您的oncreateview中执行此操作,请添加以下行:

setRetainInstance(true);

要理解此处的阅读Understanding Fragment's setRetainInstance(boolean)