187

Intro:

The basic "Fragments Tutorial" pattern goes something like this:

  1. On a tablet, have a list on the left, details on the right.
  2. Both are Fragments and both reside in the same Activity.
  3. On a phone, have a list Fragment in one Activity.
  4. Launch a new Activity with the details Fragment.

(e.g. Android 3.0 Fragments API by Dianne Hackborn and the Fragments API Guide)

On both devices, functionality is in the Fragments. (simple)

On the Tablet, the whole app is 1 Activity, on the phone, there are many Activities.


Questions:

  • Is there a reason to split the phone app into many Activities?

One problem with this method, is that you duplicate a lot of the logic in the main Tablet Activity, and in the separate Phone Activities.

  • Would it not be easier to retain the 1 Activity model in both cases, using the same logic of switching Fragments in and out (just using a different layout)?

This way most of the logic resides in the Fragments themselves, and there is only a single Activity - less duplication of code.

Also what I have read about the ActionBarSherlock is that it seems to work best with Fragments instead of Activities (but I have not worked with it yet).

Are the tutorials oversimplified, or have I missed something major in this approach?


We have tried both approaches successfully in the office - but I am about to start a bigger project and want to make things as easy for myself as possible.

Some links to related questions:


Updates

Started bounty on question - still not convinced about why I need to duplicate my app logic in my tablet activity and in each phone activity.

Also found an interesting article by the guys at Square, which is well worth reading:

Community
  • 1
  • 1
Richard Le Mesurier
  • 27,993
  • 19
  • 127
  • 242
  • 38
    +1 for an awesome, and well written question. – Siddharth Lele Sep 11 '12 at 06:44
  • that is something which pains me a lot these day, currently I am working on an application which design includes lots of fragment and it will be available in both phone and tablet, I am looking for a middle way, but couldn't find any yet... – Nixit Patel Sep 11 '12 at 07:20
  • 1
    I honestly mean no offense but I think you just accepted what you wanted to hear rather than the real answer. Scuba's answer is not recommended by Google and the blog post I liked to explains why. – pjco Sep 26 '12 at 01:11
  • @pcjo I accepted what I feel is the best Fragment code I have seen so far. If you take the google tutorial style to the complexity of a "real" app, it is easy to end up with a Tab Activity which contains logic that is also found in the various other Phone Activities. I do not like that pattern. ScubaZA & commonsware both suggest moving the logic into the fragments instead. I do like that pattern, and I think it is much better. So I think they are both "right". ScubaZA gave a more comprehensive answer, so I gave him the "accepted" & bounty. – Richard Le Mesurier Sep 26 '12 at 08:29
  • 1
    @pjco Specifically I disagree with having `onItemSelected()` method in the Activity. In my "real" app, I have many lists & sublists. This pattern suggests that my Tab Activity must have an `onItemSelected()` method to handle each of the lists. Plus the Phone Activities must each have that same logic duplicated inside each of them. IMHO it is much better to put the Item Selected logic into each Fragment - there is no duplication and I prefer that way of structuring the code. I hope this helps – Richard Le Mesurier Sep 26 '12 at 08:32
  • I appreciate your response, and agree logic should mostly exist in the fragment. It's possible some of the advantages have changed too -- when the support library came out the multi-activity setup was much more advantageous. Anyways best of luck with your project :) – pjco Sep 26 '12 at 16:56
  • 2
    I am currently hung up on this dilemma at work. Fragments load **much** faster than launching new activities, so I started to implement a single activity architecture. I ran into an issue though, which is I can't seem to find a good way to support multi-fragment configurations without doing something hacky. See [this question](http://stackoverflow.com/q/23635952/1747491). – theblang May 14 '14 at 13:26

5 Answers5

41

I agree that the tutorials are very simplified. They just introduce Fragments but I do not agree with the pattern as suggested.

I also agree that it is not a good idea to duplicate your app's logic across many Activities (see DRY Principle on wikipedia).


I prefer the pattern used by the ActionBarSherlock Fragments Demo app (download here and source code here). The demo that most closely matches the tutorial mentioned in the question is the one called "Layout" in the app; or FragmentLayoutSupport in the source code.

In this demo, the logic has been moved out of the Activity and into the Fragment. The TitlesFragment actually contains the logic for changing Fragments. In this way, each Activity is very simple. To duplicate many very simple Activities, where none of the logic is inside the Activities, makes it very simple.

By putting the logic into the Fragments, there is no need to write the code more than once; it is available no matter which Activity the Fragment is placed into. This makes it a more powerful pattern than the one suggested by the basic tutorial.

    /**
    * Helper function to show the details of a selected item, either by
    * displaying a fragment in-place in the current UI, or starting a
    * whole new activity in which it is displayed.
    */
    void showDetails(int index)
    {
        mCurCheckPosition = index;

        if (mDualPane)
        {
            // We can display everything in-place with fragments, so update
            // the list to highlight the selected item and show the data.
            getListView().setItemChecked(index, true);

            // Check what fragment is currently shown, replace if needed.
            DetailsFragment details = (DetailsFragment) getFragmentManager()
                .findFragmentById(R.id.details);
            if (details == null || details.getShownIndex() != index)
            {
                // Make new fragment to show this selection.
                details = DetailsFragment.newInstance(index);

                // Execute a transaction, replacing any existing fragment
                // with this one inside the frame.
                FragmentTransaction ft = getFragmentManager()
                    .beginTransaction();
                ft.replace(R.id.details, details);
                ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
                ft.commit();
            }

        }
        else
        {
            // Otherwise we need to launch a new activity to display
            // the dialog fragment with selected text.
            Intent intent = new Intent();
            intent.setClass(getActivity(), DetailsActivity.class);
            intent.putExtra("index", index);
            startActivity(intent);
        }
    }

Another advantage of the ABS pattern is that you do not end up with a Tablet Activity containing lots of logic, and that means that you save memory. The tutorial pattern can lead to a very big main activity in a more complex app; since it needs to handle the logic of all the fragments that get placed in it at any time.

Overall, do not think of it as being forced to use many activities. Think of it as having the opportunity to split your code into many fragments, and saving memory when using them.

Stephen Asherson
  • 1,477
  • 14
  • 23
  • thx for comprehensive answer - I have looked at the ABS demos, and I think there is a lot of good code there. I will try to move much of my logic into the Fragments instead – Richard Le Mesurier Sep 25 '12 at 08:23
  • Demo Application has moved here: https://play.google.com/store/apps/details?id=com.actionbarsherlock.sample.fragments – Philipp E. Jun 03 '13 at 16:28
  • I think the pattern you're describing is from the original Google sample code: http://android-developers.blogspot.com/2011/02/android-30-fragments-api.html I think ActionBarSherlock just ported the Google demo code to use ABS classes. – Dan J Nov 25 '13 at 19:41
17

I think you're on the right track. (And yes, the tutorials are over-simplified).

In a tablet layout, you could use a single Activity and swap in and out Fragments (in multiple 'panes'). While in a phone layout you can use a new Activity for each Fragment.

Like so:

enter image description here

It may seem like a lot of extra work, but by using multiple activities for phones, you enable basic Activity life-cycle and Intent passing. This also allows the framework to handle all the animations and the back-stack.

To help reduce the code you can use a BaseActivity and extend from that.

So if the user has a tablet you would use MyMultiPaneFragActivity or something similar. This activity is responsible for managing callbacks from the fragments and routing intents to the correct fragment (such as a search intent)

If the user has a phone, you can use a regular Activity with very little code and have it extend MyBaseSingleFragActivity or something similar. These activities could be very simple, 5-10 lines of code (maybe even less).

The tricky part is routing intents and whatnot. *(Edit: see more below).

I think the reason this is the recommended way is to save memory and reduce complexity and coupling. If you are swapping out Fragments, the FragmentManager maintains a reference to that Fragment for the back-stack. It also simplifies what should be 'running' for the the user. This setup also decouples the views and layout and logic in the Fragment from the Activity life-cycle. This way a Fragment can exist in a single activity, alongside another fragment (two-pane), or in a three-pane Activity, etc.

*One of the benefits of having regular intent routing is that you can launch an Activity explicitly from anywhere in the back-stack. One example might be in the case of search results. (MySearchResults.class).

Have a read here for more:

http://android-developers.blogspot.com/2011/09/preparing-for-handsets.html

It might be a little more up-front work, because each fragment must work well across separate activities, but it usually pays off. It means that you can use alternative layout files that define different fragment combinations, keep fragment code modular, simplify action bar management, and let the system handle all the back stack work.

pjco
  • 3,794
  • 22
  • 25
  • Re the MySearchResults advantage - you suggest having a different way of responding to that intent depending on handset or tablet - why is this better than having a single activity that responds in both cases? You suggest, on Tablet there is no regular intent routing - so you have to solve the problem for the tablet anyway. Why not use that solution on handset too? – Richard Le Mesurier Sep 11 '12 at 08:44
  • The advantage here is that your tablet code can expect to route to multiple panes. Sometimes you will want to change multiple panes on a single intent. Such as a search results on the left with the detials of the first item in the larger pane to the right. This code would not be portable to a single layout. – pjco Sep 11 '12 at 09:04
  • Why is it ok to switch fragments when there are many, but if only 1 fragment is visible, I must not switch to another fragment? – Richard Le Mesurier Sep 12 '12 at 06:46
  • Not sure I understand what you mean, but to clarify my comment above: Sometimes you may want to change more than 1 fragment at the same time in a multi-fragment layout. This requires code to change 2 fragments, that you wouldn't reuse in a single fragment layout – pjco Sep 12 '12 at 07:14
  • You're welcome :) please upvote or accept if you feel the answer is helpful – pjco Sep 12 '12 at 10:01
  • Understandable :) I'd start a bounty for you (this is a really good question) but I dont have much rep -- please feel free to ask any further questions though. I will try and update the post above to clarify with info from this discussion – pjco Sep 15 '12 at 14:11
6

Here is Reto Meier's answer regarding the same, taken from this video of Udacity's Android Fundamentals course.

There are a number of reasons you'd be better off breaking your app into different activities.

  • Having a single monolithic activity increases the complexity of your code, making it difficult to read, test and maintain.
  • Makes creating and managing intent filters much harder.
  • Increases the risk of tightly coupling independent components.
  • Makes it much more likely to introduce security risks if the single activity includes both sensitive information and information that's safe to share.

A good rule of thumb is to create a new activity whenever the context changes. For example, displaying a different kind of data and while switching from viewing to entering data.

Community
  • 1
  • 1
Aditya Naique
  • 1,010
  • 12
  • 21
4

One problem with this method, is that you duplicate a lot of the logic in the main Tablet Activity, and in the separate Phone Activities.

In the master-detail pattern, there are two activities. One shows both fragments on larger screens and only the "master" fragment on smaller screens. The other shows the "detail" fragment on smaller screens.

Your detail logic should be tied up in the detail fragment. Hence, there is no code duplication related to detail logic between activities -- the detail activity merely displays the detail fragment, perhaps passing in data from an Intent extra.

Also what I have read about the ActionBarSherlock is that it seems to work best with Fragments instead of Activities (but I have not worked with it yet).

ActionBarSherlock has no more to do with fragments than does the native action bar, since ActionBarSherlock is purely a backport of the native action bar.

CommonsWare
  • 910,778
  • 176
  • 2,215
  • 2,253
  • What are your thoughts on the idea of a single activity? – theblang May 14 '14 at 13:29
  • @mattblang: So long as you get the navigation right, there's no problem with that. – CommonsWare May 14 '14 at 14:33
  • 1
    I have tried refactoring to a single activity architecture because replacing a fragment is so much faster than launching a new activity with that same fragment in it. I feel like I am running into too many snags though, like [this](http://stackoverflow.com/q/23635952/1747491). Most examples I find online, particularly for multi-fragment configurations like master-detail, don't use a single activity. So I am in a bit of a dilemma. – theblang May 14 '14 at 14:36
0

Referring to the 1st question of "Is there a reason to split the phone app into many Activities?" - Yes. it simply comes down to the space available, a Tablet gives more room to developers, thus allowing developers to put more on one screen. Android tells us that Activities can provide a screen. So What you can do with 1 large screen on a tablet, is something that may have to be spread across multiple screens on a phone, because there's not enough room for all of the fragments.

EFlisio
  • 51
  • 5
  • 1st sentence - "An Activity is an application component that **provides a screen** with which users can interact in order to do something, ". I do see an error in my original statement, I didn't mean to put "are another screen", – EFlisio May 24 '15 at 17:10