在两个片段之间传递数据:NullPointerException

时间:2014-08-16 11:04:43

标签: android android-fragments

我有一个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;
        }

    }
}

片段1:

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的字段?

3 个答案:

答案 0 :(得分:1)

关于生命周期似乎有问题。您可能知道,onCreateView()是异步方法,因此可以在setAdapter()之前访问片段实例。

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

答案 1 :(得分:0)

如果寻呼机从未显示过第二个片段,则在调用fragment1接口回调时,寻呼机返回null:

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

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

答案 2 :(得分:0)

问题出在PagerAdapter之内。我使用getItem()来接收绑定到标签位置的Fragment。错误是我返回了Fragment的新实例,而不是返回现有的Fragment。由于新的Fragment从未显示过Fragment的{​​{1}},因此onCreateView()从未被调用过。这就是我在

中收到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(); } } ,但我认为解决方案是可理解的。