在两个fragment之间传递数据:NullPointerException



我有一个Activity主机两个Fragments。一个包含EditText,一个显示GridView的输入。Fragment1实现了一个接口,当用户想要保存输入时通知用户。在Activity中,我想将数据传递给Fragment2的ArrayAdapter,但在这里我得到了NullPointerException

活动:

public class SwipeTest extends FragmentActivity implements TestFragment1
                                                               .OnFragmentInteractionListener {
    private final String[] tabs = {"Test 1", "Test 2"};
    private ViewPager        pager;
    private ActionBar        actionBar;
    private TabsPagerAdapter adapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.pager = new ViewPager(this);
        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup
                                                                       .LayoutParams.MATCH_PARENT,
                                                                   ViewGroup
                                                                       .LayoutParams.MATCH_PARENT);
        this.pager.setLayoutParams(params);
        setContentView(this.pager);
        this.actionBar = getActionBar();
        this.adapter = new TabsPagerAdapter(
            getSupportFragmentManager());
        this.pager.setAdapter(this.adapter);
        this.actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
        setUpViewPager();
        setUpActionBar();
    }
    /**
     * Sets up the ViewPager and adds an OnPageChangeListener
     */
    private void setUpViewPager() {
        this.pager.setAdapter(this.adapter);
        // pager needs an id; crashes if it has none
        this.pager.setId(123456789);
        // Set up the listener
        ViewPager.OnPageChangeListener onPageChangeListener = new ViewPager
            .OnPageChangeListener() {
            @Override
            public void onPageScrolled(int i, float v, int i2) {
            }
            @Override
            public void onPageSelected(int i) {
                SwipeTest.this.actionBar.setSelectedNavigationItem(i);
            }
            @Override
            public void onPageScrollStateChanged(int i) {
            }
        };
        this.pager.setOnPageChangeListener(onPageChangeListener);
    }
    /**
     * Sets up the ActionBar with it's tabs and adds an ActionBar.TabListener to
     * them
     */
    private void setUpActionBar() {
        this.actionBar = getActionBar();
        this.actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
        // Set up listener
        ActionBar.TabListener tabListener = new ActionBar.TabListener() {
            @Override
            public void onTabSelected(ActionBar.Tab tab,
                                      FragmentTransaction
                                          fragmentTransaction) {
                SwipeTest.this.pager.setCurrentItem(tab.getPosition());
            }
            @Override
            public void onTabUnselected(ActionBar.Tab tab,
                                        FragmentTransaction
                                            fragmentTransaction) {
            }
            @Override
            public void onTabReselected(ActionBar.Tab tab,
                                        FragmentTransaction
                                            fragmentTransaction) {
            }
        };
        for (String tab_name : this.tabs) {
            this.actionBar.addTab(
                this.actionBar.newTab()
                              .setText(tab_name)
                              .setTabListener(tabListener));
        }
    }
    /**
     * Interface method of Fragment1
     */
    @Override
    public void onFragmentInteraction(String s) {
        // This gets the fragment correct
        TestFragment2 fragment = (TestFragment2) ((TabsPagerAdapter) pager
            .getAdapter()).getItem(1);
        // This assigns null to adapter
        ArrayAdapter<String> adapter = (ArrayAdapter<String>) fragment
            .getAdapter();
        adapter.add(s);
        adapter.notifyDataSetChanged();
    }

    public class TabsPagerAdapter extends FragmentPagerAdapter {
        public TabsPagerAdapter(FragmentManager fm) {
            super(fm);
        }
        @Override
        public Fragment getItem(int index) {
            switch (index) {
                case 0:
                    return new TestFragment1();
                case 1:
                    return new TestFragment2();
            }
            return null;
        }
        @Override
        public int getCount() {
            return 2;
        }
    }
}

Fragment1:

public class TestFragment1 extends Fragment {
    private OnFragmentInteractionListener mListener;
    private EditText                      edit;
    public TestFragment1() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.MATCH_PARENT);
        LinearLayout layout = new LinearLayout(getActivity());
        layout.setLayoutParams(params);
        this.edit = new EditText(getActivity());
        Button btn = new Button(getActivity());
        btn.setText("Save");
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                onButtonPressed();
            }
        });
        layout.addView(this.edit);
        layout.addView(btn);
        return layout;
    }
    public void onButtonPressed() {
        if (this.mListener != null) {
            String input = this.edit.getText().toString();
            this.mListener.onFragmentInteraction(input);
        }
    }
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            this.mListener = (OnFragmentInteractionListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                                             + " must implement " +
                                             "OnFragmentInteractionListener");
        }
    }
    @Override
    public void onDetach() {
        super.onDetach();
        this.mListener = null;
    }
    public interface OnFragmentInteractionListener {
        public void onFragmentInteraction(String s);
    }
}

Fragment2:

public class TestFragment2 extends Fragment {
    private final List<String> data = new ArrayList<String>();
    private ArrayAdapter<String> adapter;
    public TestFragment2() {
        // Required empty public constructor
    }
    public ArrayAdapter getAdapter() {
        return this.adapter;
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        GridView view = new GridView(getActivity());
        GridView.LayoutParams params = new AbsListView.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.MATCH_PARENT);
        view.setLayoutParams(params);
        this.data.add("Hello");
        this.data.add("World");
        this.adapter = new ArrayAdapter(getActivity(),
                                        android.R.layout
                                            .simple_list_item_1,
                                        this.data);
        view.setAdapter(this.adapter);
        return view;
    }

}

我不知道为什么ArrayAdapter<String> adapter = (ArrayAdapter<String>) fragment.getAdapter();是空的。那么,我如何访问Fragment2的字段?

这似乎是生命周期的问题。你可能知道,onCreateView()是异步方法,所以片段实例可以在setAdapter()之前访问。

我的建议是在swipetest# onCreate()中创建TestFragment2实例。此外,每次按下按钮时,代码都会创建新的实例。这似乎不是个好主意。

问题在PagerAdapter内部。我使用getItem()来接收绑定到标签位置的Fragment。错误是我返回了该Fragment的新实例,而不是返回现有的Fragment。由于新的Fragment从未显示过FragmentonCreateView(),因此setUpAdapter()从未被调用过。这就是为什么我在

中收到NPE
ArrayAdapter<String> adapter = (ArrayAdapter<String>) fragment
    .getAdapter();
adapter.add(s);

方法[*]:

public class TabsPagerAdapter extends FragmentPagerAdapter {
    private final List<Fragment> mFragments = new ArrayList<Fragment>();
    public TabsPagerAdapter(FragmentManager fm) {
        super(fm);
        mFragments.add(0, new TestFragment1());
        mFragments.add(1, new TestFragment2());
    }
    @Override
    public Fragment getItem(int index) {
        if (index > (mFragments.size() - 1) )
            return null;
        return mFragments.get(index);
    }
    @Override
    public int getCount() {
        return mFragments.size();
    }
}

[*]未经测试,因为我改变了我的代码,不再使用PagerAdapter,但我认为解决方案是可以理解的

如果分页器从未显示第二个片段,当调用fragment1接口回调时,分页器返回null:

// This gets the fragment correct
TestFragment2 fragment = (TestFragment2) ((TabsPagerAdapter) pager
    .getAdapter()).getItem(1);

因此,随后对getAdapter()的调用将导致NPE。

最新更新