Kurztipp
Kurztipp

Reputation: 411

Passing data between two Fragments: NullPointerException

I'm having an Activity that hosts two Fragments. One which contains an EditText and one that shows the input in a GridView. Fragment1 implements an interface to notify when the user wants to save the input. In the Activity I want to pass the data to the ArrayAdapter of Fragment2 but here I get the NullPointerException.

Activity:

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;
    }


}

I don't know why ArrayAdapter<String> adapter = (ArrayAdapter<String>) fragment.getAdapter(); is null. So, how do I get access to the fields of Fragment2?

Upvotes: 0

Views: 297

Answers (3)

Larry Schiefer
Larry Schiefer

Reputation: 15775

If the pager has never shown the second fragment, when your fragment1 interface callback is called the pager returns null:

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

So your subsequent call to getAdapter() will result in the NPE.

Upvotes: 0

Kurztipp
Kurztipp

Reputation: 411

The problem was within the PagerAdapter. I used getItem() to recieve the Fragment which is bound to the tab's position. The mistake was that I returned a new instance of that Fragment instead of returning the existing Fragment. Since that new Fragment has never been shown the Fragment's onCreateView() and hence setUpAdapter() has never been called. That's why I recieved NPE in

ArrayAdapter<String> adapter = (ArrayAdapter<String>) fragment
    .getAdapter();
adapter.add(s);

Approach[*]:

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();
    }

}

[*] Untested since I changed my code and don't use the PagerAdapter anymore but I think the solution is comprehensible.

Upvotes: 0

muumuutech
muumuutech

Reputation: 166

It seems problem about lifecycle. As you may know, onCreateView() is async method, so fragment instance could be accessed before setAdapter().

My suggestion is to create TestFragment2 instance in SwipeTest#onCreate(). Also, your code creates new instance every time button pressed. It seems not good idea.

Upvotes: 1

Related Questions