Fragment question: inter-fragment communication?

5767 views
Skip to first unread message

davemac

unread,
Feb 17, 2011, 11:10:17 PM2/17/11
to Android Developers
I'd love to hear opinions on the best way to communicate between
fragments.

If we consider that fragments are like sub-activities (a common
metaphor), then we might think to use broadcast messages to tell one
fragment about something that happened in another fragment. That seems
a bit difficult though not impossible.

The samples simply lookup one fragment from another then access views
directly. This forces that fragment to understand what's going on
around it, which doesn't feel as object-oriented as I'd like. I'd feel
better if maybe the activity was doing that sort of coordination, so
the fragment tells the activity, and the activity figures out which
other fragment, if any, needs to get a message, then invokes a method
on the fragment so it can perform any updates. Or the activity could
decide we're in a situation where we need to fire up a separate
activity. Or maybe move things around on the screen.

Am I over-complicating things here? I realize that a mobile app should
be as compact as possible, and if that means "just do it" and access
views in other fragments directly, then I could go along with that.
But I thought I'd ask the group to get some other opinions.

- dave

Streets Of Boston

unread,
Feb 17, 2011, 11:39:22 PM2/17/11
to android-d...@googlegroups.com
Your 'activity' idea seems to be the best one.
 
Fragments can be used to better separate Views from Controllers, where Fragments (and it constituent child-views) are the Views and Activities are the Controllers (note that Activities would still 'directly' update the action-bar, the title-bar, options-menu, etc).
 
You can add your own methods to Fragments. These methods can register listeners or they can update the state/appearance of a Fragment.
 
An Activity registers a listener (e.g. Fragment.set/addOnXXXXXListener methods) with one Fragment. When the listener (e.g. the listener.onXXXX method) gets called by a Fragment, the Activity updates another Fragment in response.
 
This way, one Fragment does not need to know anything about other Fragments, maintaining a nice separation.
 

Dianne Hackborn

unread,
Feb 18, 2011, 1:13:06 AM2/18/11
to android-d...@googlegroups.com
No, actually, one of the big benefits of fragments is that they are *not* sub-activities, they don't try to have a pretense of being isolated from each other, and are designed to allow you to easily use direct pointers to them.

Don't try to impose "object oriented" because you feel like this somehow magically makes things better.  Unless it serves a purpose, it doesn't.

Anyway there is a perfectly fine way to do these interactions that most people will agree is object oriented and makes the code much simpler and lighter weight: define a callback interface that one fragment (or activity) implements and another can then call.

See for example the built-in facility for a fragment to have a pointer to a target fragment.  This is the fragment version of activity's onActivityResult().  However because fragments don't have a goal of imposing a strict (remote-able) high-level interface to itself, sending results between fragments is a lot easier: just define an interface of whatever functionality you want, which the target fragment can implement, and the sending can cast and call on.

You can also take advantage of the FragmentManager APIs to save a fragment "pointer" in a bundle and later retrieve it, to allow you to maintain direct pointers across state save/restore.

Basically, with fragments you'll want to unlearn a lot of the painful things you got used to dealing with in embedded activities. :)


--
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to android-d...@googlegroups.com
To unsubscribe from this group, send email to
android-develop...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en



--
Dianne Hackborn
Android framework engineer
hac...@android.com

Note: please don't send private questions to me, as I don't have time to provide private support, and so won't reply to such e-mails.  All such questions should be posted on public forums, where I and others can see and answer them.

davemac

unread,
Feb 18, 2011, 8:19:39 AM2/18/11
to Android Developers
I had seen and appreciate the putFragment() method of FragmentManager.
Quick follow-on question on that: you aren't necessarily guaranteed to
get back the same in-memory instance of a fragment saved with
putFragment() when you call getFragment(), but you won't be able to
tell the difference, unless you've used internal variables and not
saved/restored them in onSaveInstanceState() and one of the startup
callbacks, correct?

I had not fully understood the meaning and use of target fragments.
The FragmentRetainInstance example under API Demos is helpful in this
regard.

If fragment A wants to communicate with fragment B, I'm assuming that
fragment A must know whether or not fragment B is part of the current
activity, or would be in a separate activity (in the case this is
running on a smaller screen, or just because). Is that also true? I'm
assuming that a fragment manager is per activity, and that a fragment
in a different activity should not be directly "talking" to a fragment
in the first activity.

- dave
> hack...@android.com

Dianne Hackborn

unread,
Feb 18, 2011, 1:09:39 PM2/18/11
to android-d...@googlegroups.com
On Fri, Feb 18, 2011 at 5:19 AM, davemac <davem...@gmail.com> wrote:
I had seen and appreciate the putFragment() method of FragmentManager.
Quick follow-on question on that: you aren't necessarily guaranteed to
get back the same in-memory instance of a fragment saved with
putFragment() when you call getFragment(), but you won't be able to
tell the difference, unless you've used internal variables and not
saved/restored them in onSaveInstanceState() and one of the startup
callbacks, correct?

Correct, you won't get back the same instance, and should not do anything that relies on it being the same instance when your own fragment/activity is being created.
 
If fragment A wants to communicate with fragment B, I'm assuming that
fragment A must know whether or not fragment B is part of the current
activity, or would be in a separate activity (in the case this is
running on a smaller screen, or just because). Is that also true? I'm
assuming that a fragment manager is per activity, and that a fragment
in a different activity should not be directly "talking" to a fragment
in the first activity.

You should never, ever get yourself into a situation where two fragments have references to each other but are not part of the same activity.  So yes, there is one FragmentManager instance per activity.  Activity is still the high-level self-contained object that others only indirectly interact with (through startActivity() etc); FragmentManager and Fragment are implementation details within a particular activity, making it easier to build more complicated activities.

--
Dianne Hackborn
Android framework engineer
hac...@android.com

Gregg Reno

unread,
Feb 27, 2011, 9:39:49 PM2/27/11
to Android Developers
Maybe this covered earlier in this thread and I'm still not
understanding it. I like the idea of a each fragment communicating
back to the activity rather than to other fragments. Then the activity
can decide whether it needs to send information to other fragments.

So is there an existing mechanism for a fragment to send a message to
the activity? If not, I guess I could just create a handler in the
activity and pass the handler pointer to the fragment so it can send a
message to the activity.

My use case is the activity is responsible for all changes to the
action bar and to showing or hiding various fragments.

Thanks,
-Gregg Reno

Dianne Hackborn

unread,
Feb 27, 2011, 9:53:21 PM2/27/11
to android-d...@googlegroups.com, Gregg Reno
Fragment.getActivity().doSomething().

A little more formally, define an interface for the fragment to call back on the activity it is running in, which each activity using that fragment can implement.


--
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to android-d...@googlegroups.com
To unsubscribe from this group, send email to
android-develop...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en

Gregg Reno

unread,
Feb 27, 2011, 9:58:18 PM2/27/11
to Dianne Hackborn, android-d...@googlegroups.com

OK, that makes sense.  Thanks Dianne.
-Gregg

davemac

unread,
Feb 27, 2011, 11:59:48 PM2/27/11
to Android Developers
A little more formally, have your activity implement an interface such
as OnMyFragmentListener, so that the activity must implement a method
like onFragmentDidSomething(). When your fragment wants to send
something to the activity, it can do the following:

((OnMyFragmentListener)getActivity()).onFragmentDidSomething(...);

You will get a ClassCastException in your fragment if the activity
didn't implement the interface, but the really nice thing is that from
your fragment's point of view, it doesn't have to care exactly which
activity did the invoking. The cast is to the interface, not the
activity. You could put the Listener interface definition inside your
fragment class to keep things nice and clean.

- dave

On Feb 27, 9:58 pm, Gregg Reno <gregg.r...@gmail.com> wrote:
> OK, that makes sense.  Thanks Dianne.
> -Gregg
> On Feb 27, 2011 9:53 PM, "Dianne Hackborn" <hack...@android.com> wrote:
>
> > Fragment.getActivity().doSomething().
>
> > A little more formally, define an interface for the fragment to call back
> on
> > the activity it is running in, which each activity using that fragment can
> > implement.
>
> > On Sun, Feb 27, 2011 at 6:39 PM, Gregg Reno <gregg.r...@gmail.com> wrote:
>
> >> Maybe this covered earlier in this thread and I'm still not
> >> understanding it. I like the idea of a each fragment communicating
> >> back to the activity rather than to other fragments. Then the activity
> >> can decide whether it needs to send information to other fragments.
>
> >> So is there an existing mechanism for a fragment to send a message to
> >> the activity? If not, I guess I could just create a handler in the
> >> activity and pass the handler pointer to the fragment so it can send a
> >> message to the activity.
>
> >> My use case is the activity is responsible for all changes to the
> >> action bar and to showing or hiding various fragments.
>
> >> Thanks,
> >> -Gregg Reno
>
> >> --
> >> You received this message because you are subscribed to the Google
> >> Groups "Android Developers" group.
> >> To post to this group, send email to android-d...@googlegroups.com
> >> To unsubscribe from this group, send email to
> >> android-develop...@googlegroups.com
> >> For more options, visit this group at
> >>http://groups.google.com/group/android-developers?hl=en
>
> > --
> > Dianne Hackborn
> > Android framework engineer
> > hack...@android.com

Dianne Hackborn

unread,
Feb 28, 2011, 2:10:11 AM2/28/11
to android-d...@googlegroups.com, davemac
You can also do the cast in Fragment.onAttach() if you want to fail quickly in the case of someone forgetting to implement the interface.
hac...@android.com

Gregg Reno

unread,
Feb 28, 2011, 9:43:00 AM2/28/11
to Android Developers
Thanks for all the help on this. I'm not the greatest Java
programmer, but thought I would share my code in case it's useful to
anyone else.

In my case, I'm trying to replicate the functionality similar to the
email client. I have 3 fragments - a list view, a gallery view, and a
content view. At start up, I show only the list view and gallery
view. When a user clicks on a title in the gallery view, I hide the
list view, slide the gallery view over to the left, display the
content view and tell the content view which title to show. The flow
then is the gallery fragment tells the activity what title was
selected, the activity updates the UI and calls a method in the
content fragment.

Here is my code. I tried to make it as generic as possible, but it
probably doesn't have enough error handling.

=== FragmentNotification.java ===

import android.app.Fragment;

//Allows a fragment to notify an activity of an event
public interface FragmentNotification
{
public static final int FRAG_ACTION_TITLE_SELECTED = 1;

// actionInt and actionString are optional depending on actionType
void fragmentAction(Fragment fragID, int actionType, int actionInt,
String actionString );
}

=== GalleryFragment.java ===

gView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int
position, long id)
{
rTitle = xmlparse.results.RecordList.get(position);

GalleryFragment galleryFrag = (GalleryFragment)
getFragmentManager()
.findFragmentById(R.id.frag_gallery);

((FragmentNotification)getActivity()).fragmentAction
(galleryFrag, FragmentNotification.FRAG_ACTION_TITLE_SELECTED,
0, rTitle.sTitleId);

}
});

=== MainActivity.java ===

...
public class MainActivity extends Activity implements
FragmentNotification, ActionBar.TabListener,
SearchView.OnQueryTextListener, SearchView.OnCloseListener,
Button.OnClickListener,
{
...

//Receive an event notification from a fragment
@Override
public void fragmentAction(Fragment fragID, int actionType, int
actionInt, String actionString)
{
if (fragID == fragGallery)
{
if (actionType == FragmentNotification.FRAG_ACTION_TITLE_SELECTED)
{
//Update user interface
if (detailState != DETAIL_STATE_DETAIL)
setDetailState(DETAIL_STATE_DETAIL);

//Tell content frag to display title
fragContent.displayTitle(actionString);
}
}

}
...
}

Reply all
Reply to author
Forward
0 new messages