3

I basically have a MainActivity that has multiple tabs. Each tab is a ShowListFragment and it extends Fragment. Now, each tab contains data that I fetch from a database. I have a MOVE-button that moves data from one tab to another in each Fragment:

@Override
public void onClick(DialogInterface dialog, int listIndex) {
    database.add(listIndex,object);
    database.remove(listIndex,object);
}

The fragment does not update directly, but after a few swipes in between the tabs (3 exactly). How do I force the Fragment to update instantaneous after I clicked the button? I don't want to manage it through onPageSelected in the ViewPager, since it does not update the fragment I'm currently on, but after I've swiped to the next fragment. And also I don't want to update the data after each swipe.

I know that I maybe need to use some kind of observer pattern like this: How do I make a Class extend Observable when it has extended another class too? But still, I'm still not sure how to update the fragment directly, and how to apply the observer/event pattern in my application.

Community
  • 1
  • 1
user2097519
  • 55
  • 1
  • 7

1 Answers1

26

Updated Answer:

With Android architecture components, doing this is much simpler.

The recommended pattern is using a ViewModel with LiveData members. Your fragments will register observers on the LiveData members which will automatically be coordinated with lifecycle events, e.g. unregistering in onDestroy() etc. https://developer.android.com/topic/libraries/architecture/livedata

When using the Navigation component, you can pass data when navigating to a fragment: https://developer.android.com/guide/navigation/navigation-pass-data

You can also return data from the navigated fragment: https://developer.android.com/guide/navigation/navigation-programmatic


Old answer (superseded by Architecture Components):

Since the fragments can access the activity easily enough with getActivity(), I would make the activity be the central hub for dispatching updates.

It sounds like you already have the persistence part handled with the database and all you need is some update events. So here goes:

  1. Define a listener interface. I usually do this as an inner interface within the activity:

         public interface DataUpdateListener {
             void onDataUpdate();
         }
    
  2. Add a data structure to your activity to keep track of listeners:

         private List<DataUpdateListener> mListeners;
    

Don't forget to initialize in the constructor:

            mListeners = new ArrayList<>();
  1. Add the register/unregister methods to the activity:

         public synchronized void registerDataUpdateListener(DataUpdateListener listener) {
             mListeners.add(listener);
         }
    
         public synchronized void unregisterDataUpdateListener(DataUpdateListener listener) {
             mListeners.remove(listener);
         }
    
  2. Add the event method to your activity:

         public synchronized void dataUpdated() {
             for (DataUpdateListener listener : mListeners) {
                 listener.onDataUpdate();
             }
         }
    
  3. Have your fragments implement DataUpdateListener:

     public class MyFragment extends Fragment implements DataUpdateListener {
    

and implement the method

        @Override
        public void onDataUpdate() {
            // put your UI update logic here
        }
  1. Override onAttach() and onDestroy() in the fragments to register/unregister:

         @Override
         public void onAttach(Activity activity) {
             super.onAttach(activity);
             ((MainActivity) activity).registerDataUpdateListener(this);
         }
    
         @Override
         public void onDestroy() {
             super.onDestroy();
             ((MainActivity) getActivity()).unregisterDataUpdateListener(this);
         }
    
  2. Fire the event in your fragment's UI update event:

         @Override
         public void onClick(DialogInterface dialog, int listIndex) {
             database.add(listIndex,object);
             database.remove(listIndex,object);
             ((MainActivity) getActivity()).dataUpdated();
         }
    
kris larson
  • 30,387
  • 5
  • 62
  • 74
  • I've added your steps above, and onDataUpdate() is called when the button is clicked. But I'm still not sure how to update the fragment directly "// put your UI update logic here" in step 5. I tried to attach/detach the fragment and then commit the change, but still no luck. – user2097519 Jun 12 '16 at 00:29
  • 1
    You don't need to change fragments; the `ViewPager` and `PagerAdapter` handle all that. The UI update logic is probably just re-querying the database to pick up what was changed in the other fragment and calling `notifyDataSetChanged` on an adapter. You see, with a `ViewPager`, even though the fragments to the left and to the right of the currently displayed fragment aren't visible, they are still in memory and active. They will get the event that is fired from the visible fragment. Update the fragment when the event is fired, then when you swipe back to the fragment it will be in sync. – kris larson Jun 13 '16 at 05:43
  • Hi kris thanks for the great answer but i am getting other problem when i follow this approach.when i put idle sometime and again click on button in the fragment getting following exception`Fragment GoldPackageFragment{effed52} not attached to Activity at android.support.v4.app.Fragment.getResources(Fragment.java:646) at com.subscription.GoldPackageFragment.onDataUpdate(GoldPackageFragment.java:729)` – malli Oct 26 '17 at 07:53
  • @malli We need more information. Post a new question with your relevant code and the stack trace so that the entire community has an opportunity to look at it and one of us should be able to help you. – kris larson Oct 26 '17 at 14:04