Android – Refresh fragment view when button is clicked

androidandroid-fragmentsview

I have a fragment activity that uses a ViewPager to display a set of fragments. On the fragment activity I have a button that when clicked, it sends a message to the current fragment to refresh its contents. Everything works ok (activity / current fragment communication) except the fact that I cannot refresh the fragment's view. Accessing the current view by getView() does not work as this function returns null; it seems that after the fragment is created (on ViewCreated is called) getView gets destroyed. Am I missing something here? How to I cause a fragment to redraw its contents programmatically? It seems that the only way this works is when the fragment is created from the parent activity. Do I have to remove and re-add the fragment again to do this?

Here is the code:

The main activity:

public class MainActivity extends FragmentActivity {

    private MyAdapter mAdapter;
    private static ViewPager mPager;

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

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

        @Override
        public boolean onPrepareOptionsMenu(Menu menu) {
                return super.onPrepareOptionsMenu(menu);
        }

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
                switch (item.getItemId()) {

                case R.id.menu_test:
                        updateFragment();
                        return true;

                default: return true;
                }
        }

        private void updateFragment() {
                for (int i=0; i< mAdapter.getCount(); i++) {
                        SampleFragment fragment = (SampleFragment) mAdapter.getItem(i);
                        fragment.update();
                }
        }

        private void setupViewPager() {
                try {
                        mAdapter = new MyAdapter(getSupportFragmentManager());

                        mPager = (ViewPager) findViewById(R.id.pager);
                        mPager.setAdapter(this.mAdapter);

                } catch (Exception e) {
                        e.printStackTrace();
                }
        }

        public class MyAdapter extends FragmentPagerAdapter {

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

                @Override
                public Fragment getItem(int position) {
                        SampleFragment fragment = new SampleFragment(position); 
                        return fragment;
                }

                @Override
                public int getCount() {
                        return 5;
                }
        }
}

and the fragment class:

public class SampleFragment extends Fragment{

        private int myPosition = -1;

        public SampleFragment(int position) {
                this.myPosition = position;
        }

        @Override
        public void onAttach(Activity activity) {
                super.onAttach(activity);
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
                View view = inflater.inflate(R.layout.fragment, container, false);
                update(view, "Updated from onCreateView");
                return view;
        }

        @Override
        public void onActivityCreated(Bundle bundle) {
                super.onActivityCreated(bundle);
        }

        @Override
        public void onViewCreated(View view, Bundle savedInstanceState) {
                super.onViewCreated(view, savedInstanceState);

                view.findViewById(R.id.textTitle).setOnClickListener(myClickListener);
        }

        private OnClickListener myClickListener = new OnClickListener() {
                @Override
                public void onClick(View v) {
                        switch (v.getId()) {

                        case R.id.textTitle:
                                break;

                        }
                }
        };

        public void update() {
                update(getView(), "Updated from main");
        }

        private void update(View view, String subtitleText) {
                TextView title = (TextView) view.findViewById(R.id.textTitle);
                TextView subtitle = (TextView) view.findViewById(R.id.textSubtitle);

                title.setText("Fragment " + myPosition);
                subtitle.setText(subtitleText);
        }
}

The error happens on view.FindViewById (view is null) when called from the menu item in the main activity.

Best Answer

You can take a look at this article which explains how to keep references to the fragments in your ViewPager.

There are two methods described on the page. The first one involves setting a tag when you add the fragment using the FragmentManager. Then you can retrieve the fragment using findFragmentByTag(). However, I did not see how to make this work using FragmentPagerAdapter or FragmentStatePagerAdapter, since these implementations add the fragments for you. If you are using your own custom PagerAdapter, this may work for you.

The other method, which does work for FragmentPagerAdapter or FragmentStatePagerAdapter, involves keeping a map of all your fragments, updating inside your getItem() and destroyItem() implementations. This method has worked for me.

Once you have a reference to the current fragment, you can just call a method in your fragment to refresh its view.