6

The problem as follows. Let us have 3 tabs with fragments:

  • Tab 1 (Fragment A). Needs to send data to Tab 2.
  • Tab 2 (Fragment B). Needs to receive data from Tab 1.
  • Tab 3 (Fragment B). Already contains data.

As you see Tab 3 and Tab 2 contain the same Fragment but different instances.

How do I send data (not via arguments) to exactly Tab 2?

What I've tried:

  1. Set the unique ID for Fragment B via arguments when they were created.
  2. Register same Local Broadcast Receiver for both instances of Fragment B
  3. Send data from Fragment A to Fragment B with its ID
  4. In Fragment B onReceive() check if recevied ID equals ID of Fragment

But unfortunately broadcast was sent to Tab 3 only.


EDIT: some more information.

Those tabs are hosted inside another fragment with ViewPager. Thats due to combination of NavigationDrawer which has fragment with ViewPager and Tabs mentioned in question.

AnZ
  • 1,040
  • 24
  • 54

5 Answers5

6

I'd suggest to introduce EventBus in your app.

To add dependency - add compile 'de.greenrobot:eventbus:2.4.0' into your list of dependencies.

Then, you just subscribe your third tab's fragment to listen to event from the first fragment.

Something like this: in Fragment B

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

@Override
public void onDetach() {
    eventBus.unregister(this);
    super.onDetach();
}

@SuppressWarnings("unused") // invoked by EventBus
public void onEventMainThread(NewDataEvent event) {
    // Handle new data
}

NewDataEvent.java

public class NewDataEvent extends EventBase {
    public NewDataEvent() {}
}

And in Fragment A just send the event:

protected EventBus eventBus;
....
eventBus = EventBus.getDefault();
....
eventBus.post(new NewDataEvent());

(and to avoid handling event in 2nd tab - just pass extra parameter during instantiation of fragment, if it has to listen to the event)

Konstantin Loginov
  • 15,802
  • 5
  • 58
  • 95
  • Event-Driven Development, huh? That's interesting approach. Gooing to give it a try. Thank you! – AnZ Dec 12 '15 at 16:28
5

Are the fragments hosted in one activity? Then you could implement an interface on your hosting activity.

YourActivity implements MyInterface {
...
}

And in your fragments you define this:

@Override
public void onAttach(final Activity context) {
  myInterface = (MyInterface) context;
}

And when you click something in your fragment then call myInterface.doSomething(parameter);. And then your activity can delegate to another fragment.

Thomas R.
  • 7,988
  • 3
  • 30
  • 39
  • This is the proper way of doing it! – Skynet Dec 10 '15 at 10:54
  • Thanks for quick reply. Those fragments are hosted in one fragment (because I have NavigationDrawer with fragment which contains ViewPager with those tabs). But anyway, I've got your point. Going to give it a try. – AnZ Dec 10 '15 at 11:01
  • Sorry for desinformation, but seems like this approach doesn't work for fragments hosted inside fragment. I'm receiving `ClassCastException` in `OnAttach()`. Going to edit question – AnZ Dec 10 '15 at 11:18
  • If they are hosted in a viewpager you should handle this in your viewpager adapter. Each fragment should correspond to a specific position, and you can update your fragments. – Thomas R. Dec 10 '15 at 11:27
  • @ThomasR., I don't really understand how can I use interface in adapter. Could you edit your answer to give me some hints? Or perhabs that can be achieved without interfaces? – AnZ Dec 11 '15 at 08:21
  • Are the fragments hosted in a viewpager? If yes, then the interface implementation is obsolete. If you are using a viewpager than you can handle your fragments using the viewpager adapter. – Thomas R. Dec 11 '15 at 08:47
  • [This example](http://stackoverflow.com/a/23144683/2668136) might be better to using interfaces with nested fragments. It's not `onAttach` where you init the interface but in `onAttachFragment` – Blo Dec 17 '15 at 08:11
0

You didn't write how are you adding fragments, during runtime or not. It will be better to add it during runtime and assign TAG to a each fragment, like this:

...
fragmentTransaction.replace(R.id.layoutTab2, fragment, "F-B-2");
...
fragmentTransaction.replace(R.id.layoutTab3, fragment, "F-B-3");
...

so later you can identify or find fragment by its tag. For example:

FragmentManager.findFragmentByTag("F-B-2")

or if you need fragment B 3:

FragmentManager.findFragmentByTag("F-B-3")

Hope it will help.

ivan.panasiuk
  • 1,239
  • 16
  • 20
0

You can use the idea of Bundle for passing data between Fragments. I can see that my suggestion of this idea in a previous post was misunderstood. Here is sample code where the fragment receives the data. Fragment2:

public static Fragment2 newInstance(long param1, String param2) {
    MediaFragment fragment = new Fragment2();
    Bundle args = new Bundle();

    args.putLong(ARG_PARAM1, param1);
    args.putString(ARG_PARAM2, param2);

    fragment.setArguments(args);
    return fragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getArguments() != null) {
        Bundle bundle = getArguments();
        audioId = bundle.getLong(ARG_PARAM1);
        audioName = bundle.getString(ARG_PARAM2);
    }
}

On another fragment or activity, calling Fragment2:

Fragment2 recvfragment = Fragment2.newInstance(itemId, itemName);

Notes:

  • With Bundles, you can pass specific data types with the values into different instances of the Fragment, which you require.
  • In this case, the code is passing a Long and String type onto Fragment2.
The Original Android
  • 6,147
  • 3
  • 26
  • 31
  • if you see my question carefully you will see that data passing via arguments is not satisfying me since data should be passed at run-time when fragments are already created – AnZ Dec 18 '15 at 08:40
  • @AnZ, In my example, you could pass a specific value to the first parameter in "newInstance(long param1...". Whichever fragment is the caller, the main activity can pass a value to a fragment, then that fragment can pass the value to the receiving fragment. This is my preferred technique since it takes less memory. And...I did try to read your post carefully. – The Original Android Dec 18 '15 at 09:00
0

If you are moving from Fragment A to Fragment B, you can simply pass values to the constructor of fragment B.

Or else if you need the same set of data to be used in all three fragments, you can use share preferences as well.

TharakaNirmana
  • 10,237
  • 8
  • 50
  • 69
  • Data is transfrered at run-time and several times. There's some event-trigerred solution is better – AnZ Dec 18 '15 at 08:38