user-44651
user-44651

Reputation: 4124

Update tabpager fragments data on Activity update

I have an Activity that has multiple fragments. The fragments all reference the data object in their MasterActivty. The MasterActivtiy may refresh its data.

How do I notify the fragments of data change?

I have tried Broadcasters and other methods, but I'm failing to understand how to do it.

I have looked at these SO questions One, two. but they didn't really make sense for my implementation. I am using a FragmentPagerAdapter to load the different tabs.

Here is my code:

MasterActivity.java

public class MasterActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_master);

 TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
        tabLayout.addTab(tabLayout.newTab().setIcon(R.drawable.ic_details));
        tabLayout.addTab(tabLayout.newTab().setIcon(R.drawable.ic_notes));

        final ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
        final PagerAdapter adapter = new TabPagerAdapter(getSupportFragmentManager(), tabLayout.getTabCount());
        viewPager.setAdapter(adapter);

        viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));

        tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                viewPager.setCurrentItem(tab.getPosition());
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });

    }

            refreshData();

    }

    public void refreshData() {
        //do a background task to get data


        //WHEN FINISHED TELL FRAGMENTS TO reloadData()

    }
    }

TabPagerAdapter.java

public class TabPagerAdapter extends FragmentPagerAdapter {

    int tabCount;

    public TabPagerAdapter(FragmentManager fm, int numberOfTabs) {
        super(fm);
        this.tabCount = numberOfTabs;
    }

    @Override
    public Fragment getItem(int position) {

        switch (position) {
            case 0:
                DetailsFragment tab1 = new DetailsFragment();
                return tab1;
            case 1:
                NotesFragment tab4 = new NotesFragment();
                return tab1;
            default:
                return null;
        }
    }

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

}

A fragment

public class DetailsFragment extends Fragment {
    private String TAG = getClass().getSimpleName();


    public DetailsFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_details, container, false);


        viewStatus = (LinearLayout) view.findViewById(R.id.viewStatus);
        scrollViewDetails = (LinearLayout) view.findViewById(R.id.scrollViewDetails);

        return view;
    }


    private void reloadData() {
        Log.i(TAG, "REALOAD DETAILS FRAGMENT");

        //Fill the text views with the data from the MasterActivity

    }

}

Upvotes: 0

Views: 39

Answers (1)

kris larson
kris larson

Reputation: 30985

The way I usually do this is:

  • Define an interface

    public interface DataReloadListener {
        void onDataReloaded(Object data); // use your data type here
    }
    
  • Give the activity the ability to register/unregister the impls (fragments)

    Add a data structure to your activity to keep track of listeners:

        private List<DataReloadListener> mListeners;
    

    Don't forget to initialize in the constructor:

            mListeners = new ArrayList<>();
    

    Add the register/unregister methods to the activity:

        public synchronized void registerDataReloadListener(DataReloadListener listener) {
            mListeners.add(listener);
        }
    
        public synchronized void unregisterDataReloadListener(DataReloadListener listener) {
            mListeners.remove(listener);
        }
    
  • Have the fragment implement the interface and register/unregister for events

        @Override
        public void onDataReloaded(Object data) {
    
            // update any fragment state here
    
            // if you are updating the UI, check that the fragment currently has a view
            if (getView() != null) {
                // update UI here
            }
        }
    

    Override onAttach() and onDetach() in the fragments to register/unregister:

        @Override
        public void onAttach(Activity activity) {
            super.onAttach(activity);
            ((MasterActivity) activity).registerDataReloadListener(this);
        }
    
        @Override
        public void onDetach() {
            ((MasterActivity) getActivity()).unregisterDataReloadListener(this);
            super.onDetach();
        }
    
  • When the event occurs, call onDataReloaded for all the registered listeners in the activity

        public synchronized void onDataReloaded(Object data) {
            for (DataReloadListener listener : mListeners) {
                listener.onDataReloaded(data);
            }
        }
    

All this infrastructure is necessary because your fragment may or may not exist at the time of the event, depending on how the user swipes.

Upvotes: 1

Related Questions