==================[ Calling between Fragments and Activities ]================== In the examples/Dialog/ code you see a rather elaborate scheme for calling functions defined in the Activity from a Fragment attached to this Activity: public class AuthDialog extends DialogFragment { /* The activity that creates an instance of this dialog fragment must * implement this interface in order to receive event callbacks. * Each method passes the DialogFragment in case the host needs to query it. */ public interface AuthDialogListener { void onDialogPositiveClick(DialogFragment dialog); void onDialogNegativeClick(DialogFragment dialog); } AuthDialogListener mListener; ... and then, in onAttach(..): @Override public void onAttach(Activity activity) { super.onAttach(activity); // Verify that the host activity implements the callback interface try { // Instantiate the NoticeDialogListener so we can send events to the host mListener = (AuthDialogListener) activity; } catch (ClassCastException e) { // The activity doesn't implement the interface, throw exception throw new ClassCastException(activity.toString() + " must implement NoticeDialogListener"); } ... } And in the Activity: public class MainActivity extends AppCompatActivity implements AuthDialog.AuthDialogListener { ... public void onDialogPositiveClick(DialogFragment dialog){ ... } public void onDialogNegativeClick(DialogFragment dialog){ ... } ... } So, you might ask: why all this complexity? Why not call functions from the MainActivity directly from the Fragment, considering that we get the reference to the activity? A first try in the Fragment could be: Activity a = getActivity(); // get the Activity we are attached to, // of null, if not yet attached. a.foo(); // for some public void foo() {..} defined in MainActivity.java This _almost_ works, but will fail to type-check. So far as the Java compiler knows, .getActivity() returns an object of type Activity, and such objects do not have a foo(). In other words, we know that .getActivity() in an attached Fragment will return a MainActivity objects in our app, which know how to call foo(), but the Java compiler doesn't, and needs to be told. So the type cast: ((MainActivity) a).foo(); and this will work. So why the whole interface game? The answer is, if you want to reuse the Fragment in different activities, you _don't_ want to litter its code with the literal name of your MainActivity. Instead, you want to make it the calling Activity's task to refer to your Fragment, by signaling in its declaration that it implements the Fragment's interface, and will indeed have the functions that the Fragment would call. This makes sense to Fragments that are written with the view of reusing them. If you only mean to use them with just one activity, then a simple type cast is enough. See the discussion in http://markmail.org/thread/sgvnc7bjtjfbh5rx#query:+page:1+mid:f7tud3ggspuwxtgb+state:results -------- [ Dianne Hackborn, Android framework engineer ]-------- 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. :) -------- > 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. 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 can also do the cast in Fragment.onAttach() if you want to fail quickly in the case of someone forgetting to implement the interface. -------- On Fri, Feb 18, 2011 at 5:19 AM, davemac 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. -------------------[ end quote ]--------------------------------------- This should clarify what the Android engineers were thinking when introducing fragments. ==================[ Different UIs for Portrait and Landscape ]============= Official Android's training offers an example of using fragments for UIs where a small screen would get one fragment at a time, but a larger screen would get two side-by-side: https://developer.android.com/training/basics/fragments/index.html However, this example presumes that any given device would just get one version of the layout, one-fragment or two-fragment, not matter how one turns the screen. Let's do one better: let switch between the one-fragment and two-fragment layouts on the _same_ device depending on its orientation. Specifically, when the screen is in portrait mode, let's show one fragment per screen, but when it's in landscape mode, let's show two fragments side-by-side, and trade these layouts on every flip. This task is a bit of a puzzle. You may have noticed that Android automatically redraws your views on flip, and even restores their contents (like the TextEdit's insides) if you give these views some IDs. This is normally what we want, but in this particular task we want to avoid it, and completely reshape the UI on a flip, with no automatically restored views lingering and getting in the way. This is very simple to do. The automatic saving and restoration of Views is implemented in onSaveInstanceState(..) and onRestoreInstanceState(..) methods inherited from the base Activity class. More specifically, onSaveInstanceState(..) packs information about the currently active views into the Bundle passed to onCreate(..) and from there to onRestoreInstanceState(..). This cluster of info is called "android:viewHierarchyState" and further includes "android:views" where the state of the Views active at the time of onSaveInstanceState(..) was saved. This is all that the Android system knows about the views of a destroyed activity, and this is what it uses to re-create them. So to suppress this functionality, you just need to override these two functions. Then you have the sole responsibility for managing the views on flip. See comments in examples/CatPicker and examples/CatPickerStatic . The latter delegates as much work as possible to the XML layout descriptions. There is a way to prevent destruction of activities and their fragments on flip. This can be achieved by specifying on the activity in the Manifest. That will change the default behavior of the activity from destroying the activity and all of its fragments on a flip to merely calling the callback onConfigurationChanged(..) In this case, you take on the extra responsibility for removing the fragments you don't want, and re-creating the UI you want. See this code and comments in examples/CatPickerWithConfigChange/ ===============[ When are Views made ready? ]=============== Fragment transactions are asynchronous. This means that you may issue a request for certain views to be removed and created, but you cannot assume that they will be available at the next line of code. In fact, calls to them at that next line might fail and crash if you try to look up the view you just issued a command to create. This is _very_ common in Android programming. For FragmentTransactions, you can force execution of pending execution before proceeding, but that still doesn't ensure their views will be ready. Your best bet is to carefully follow https://developer.android.com/guide/components/fragments.html#Lifecycle and put the functionality you need into the lifecycle callbacks that guarantee the fragment will have the resources you want created at that point. For example, once an Activity creates a Fragment, the Fragment will get its onAttach(..) called. The views of neither the fragment nor the activity are ready at that time, but methods from the activity can be called. The fragment's views will be created in onCreateView(), and onActivityCreated() will be called in the Fragment when the Activity's onCreate(..) has finished. The Fragment's Views will be made visible in onStart(), and foregrounded in onResume(), etc. Read https://developer.android.com/guide/components/fragments.html#Lifecycle for details.