Advocating Fragment Oriented Applications in Android

This is a series of 6 blog posts which explains about Fragment Oriented Architecture in Android applications. In this first post, I’m going to explain what is Fragment Oriented Architecture and why shall one care. In subsequent posts I’m going to talk about following topics.

Check out this video. It takes you on a tour through what all we’re trying to achieve in this series.

Download and set up sample application on your system, run it on a device and play with it for a while, get familiar. Also, check the README of this sample. This sample application is a blueprint of a basic NavigationDrawer based UI pattern (ActionBar has been omitted for the sake of simplicity). You can easily extract a base code out of this application and can readily build your own over it. I’ve worked on few such applications and have invested a good deal of time formulating techniques to tackle few typical requirements of this architecture. And here they are for you on a silver platter!

So, it has been long since Fragments got introduced in Android and yet its use cases aren’t very much clear among developers. Lot of us keep repulsive to it. At times due to additional code complexity and a “why bother if Activities can do it” perspective. Popularly, fragments have been considered when dealing with form-factor variations (developing apps for both Phones and Tablets) but its use is not limited to that. Getting adapted to involving fragments although would be a gradual learning process but can let you implement dynamic UI and well-structured and reusable view-controllers.

Google itself is building most of its signature UI patterns using fragments intensively. Play Store and Gmail apps are fragment oriented that use NavigationDrawer with ActionBar design patterns. Image below illustrates the pattern in these apps, showing global UI handled by activity and FrameLayout that holds fragments.

        device-2014-09-04-161221


What is fragment oriented architecture?

An android application with one activity and multiple fragments, i.e., there would be one primary activity and other screens would be fragments that would get added and removed to/from this activity as per need. Parting away from the classical belief that there is a one-to-one relationship between screens and activities, we can use full screen fragments instead to represent a screen.

Having only one activity here isn’t strictly meant. It’s flexibility lies in the very purpose of ‘Activity’ and complexity of the application at hand. An activity should deal only with a set of related functionalities. In case of small or average applications, we might actually wrap up the whole functionality within one activity. But we must spawn new activities when nature of tasks shifts. The idea is not about enforcing to limit number of activities to 1, but to better involve fragments in order to modularize the overall task of an activity into separate atomic UI components which are capable of handling a particular sub-task and managing their own life cycle.

Fragments here are to deal primarily with the UI and logic that is local to that particular UI, i.e., to act as recyclable view-controllers, leaving behind rest of global logic with activity. A fragment should stick to the context of its task. If it requires any off-context information, that should be catered by the host activity. Fragment shouldn’t bother how the activity would do it. We will talk in detail about this in ‘Inter-Fragment communication’ later.

Activity would be dealing with the following and likes:

  •     Binding together the application’s global logic.
  •     Session maintenance (app’s user, facebook, twitter, etc)
  •     Global UI (e.g., drawer in a NavigationDrawer UI)
  •     Adding/Removing Fragments and maintaining their backstack
  •     Inter-fragment communication
  •     Inter-app communication (broadcast intents, notifications, etc)


Few good reasons
I have a lot of reasons to stick to fragment oriented architecture. This didn’t occur to me on any particular day. Need, the mother of change, did it gradually. I’ve actually shifted whole applications from “Activity oriented”  to “Fragment oriented” architecture. The evolution of Android SDK seems to be advocating the use of Fragments more and more. And it’s always better to keep aligned with the parent system. You can often do without standards but the more you deviate, the more your code will break sooner or later as the system would evolve. If you’re well aligned with it, your code will be more adaptive.

Below I’m listing few points as to why fragment oriented approach shall be used.


Reusable View-Controller for various form-factors
This is the very reason they added the concept of fragment for. Applications required their UI to be redesigned to utilise the extra screen real state in tablets. Without fragments, developers would have required to write entirely different sets of activities for mobiles and tablets. With the use of fragment, a particular UI can be implemented as a reusable component which can be attached to any host activity. This famous illustration from dev site explains it well.

fragments

I would further question the use of Activity B in handset version in the illustration above. Fragment B could simply replace Fragment A and this transaction could be added to backstack to facilitate navigation back to Fragment A (lot more about transaction-backstack and its management later).

Developers often ignore this use case based on their plan to never take it to tablets. But using fragments now will set you up nicely if you change your mind in the future. There is no significant reason not to start with fragments from the beginning, where refactoring existing code to use fragments can be error-prone and will be time consuming.


For the sake of Standard Design Patterns
As I mentioned earlier, the standard design patterns in the SDK are in favour of Fragments and minimal number of activities. Following are a few leading design patterns which are not only efficient but provide really good UX at the same time thus, getting widely taken up already.

  • ActionBar with Navigation Drawer (PlayStore, Gmail)
  • ActionBar with Sliding Panel
  • Sliding Tabs with ViewPager (like in Facebook android app)

All of these patterns require you to put a global navigation UI in activity and a layout to attach/replace various fragments as per interaction with global navigation. So they stay in  single activity up to a good extent.
Except for games, most of the standard apps use one of these design patterns. We will go into implementation details of NavigationDrawer in next section.


Better control over trans-screen animations
Activity doesn’t provide much flexibility over activity-switch animations. All one can do is write animation sets in xml and provide them to activity during switch. This puts up a lot of limitations. Fragments, on the other hand, are exposed to us up to the level of its root view and container layout so we can also perform animations at view level during runtime.  Activity transition doesn’t allow partial transition of screen. Global UI will also animate out and animate back in. This won’t be a good UX. In case of fragment transition, global layout can stay at its position while rest of the view shifts. Video below shows this happening in PlayStore app. Global UI (Action Bar) remains in place while rest of the contents shift.

In addition to this, we can make use of  onCreateAnimation() method. A common way to improve android animation performance is to use hardware layers. Following code will get access to hardware acceleration during fragment switch animation.

// OVERRIDING onCreateAnimation()
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
    Animation animation = super.onCreateAnimation(transit, enter, nextAnim);
    // HW layer support only exists in API 11+
    if (Build.VERSION.SDK_INT >= 11) {
        if (animation == null && nextAnim != 0) {
            animation = AnimationUtils.loadAnimation(getActivity(), nextAnim);
        }
        if(animation != null) {
            getView().setLayerType(View.LAYER_TYPE_HARDWARE, null);
            animation.setAnimationListener(new AnimationListener() {
                public void onAnimationEnd(Animation animation) {
                    getView().setLayerType(View.LAYER_TYPE_NONE, null);
                }
            });
        }
    }
    return animation;
}


Cleaner session control
All session related code can be managed by the activity. Everything from authentication to log out. Session could be of app’s own session or of any other platform like GooglePlus or Facebook. Mostly these kind of sessions need to persist throughout the app. So a fragment oriented app can make things easier by keeping all the session related logic and information in the activity which can be utilised by any of its fragments.

Suppose an app needs to be able to post on Facebook from three of its different screens. Before posting, app would need to check if an open facebook session is available. If not, it would first start the authentication process. In a fragment oriented application, these three screens can possibly be three different fragments hosted by the same activity which contains authentication logic and fragments can ask the activity to kick off authentication whenever required. Alternatively, this can be achieved by extending activities from a base activity that is capable of managing sessions.


Cleaner deep-linking
A link to an identifiable object (user, comment, post, etc) in an application is called a deep link. For instance, in terms of world wide web, https://plus.google.com/115963077998951155402/posts would be considered a deep link as it points to a user’s page on GooglePlus using his userId. URL to someone’s Github profile or Facebook post, all are deep links. These URLs typically have params attached to identify the object. Boiled down to mobile app level, a deep link would be a set of parameters that would identify a particular object or action within the application. For instance, clicking an advertisement in mobile browser opens up GooglePlay native app pointing to certain application’s detail page, would involve a deep link. It might supply GooglePlay app the url or package name of the application and GooglePlay will deal with reacting to this request by opening up the corresponding app detail page.

In a fragment oriented app, a deep link would be received in the activity only and it would find the concerned object and spawn a fragment that can perform the required action.


Convenient inter-app communication
Fragment oriented app can have its primary activity doing the following inter-app communication.

  • Managing notifications and notification clicks.
  • Registering/Unregistering BroadcastReceivers and reacting for broadcast intents.
  • Calling up activities from other apps and receiving results
  • Location awareness, network state monitoring, etc

It’s always clean and simple to keep these interactions together and channelize them further into the app from the same point. Suppose an app needs a constant network connectivity, its activity can register a broadcast receiver to listen to changes in network state (actions android.net.conn.CONNECTIVITY_CHANGE and android.net.wifi.WIFI_STATE_CHANGED) and if network goes down, it could trigger a global UI that would show a relevant message and block any interaction with fragments until network is back up.

Note: One requirement of these kind of communications is that the host activity’s launch mode should be either singleTop or singleInstance, in order to restrict the activity from getting relaunched for each new Intent. With these LaunchModes, any further Intent would be received in activity’s onNewIntent(Intent intent) callback method if the activity is found running already. This is also required for the previous point, “Deep Links”.

In the next post of this series I’ll be talking about Transaction Backstack and few essential methods related to it.

10 thoughts on “Advocating Fragment Oriented Applications in Android

  1. Thanks for sharing long information for five helpful topic…

  2. Great post but I don’t see how Fragments are better when you use deep-linking? What do they offer?

    If you use different intent-filters for different URLs in AndroidManifest, you would get different Activities for different URLs for deep-linking. What you do with Fragments will always be manual. But with activities and IntentFilter, it is automated.

  3. The advantage lies in having more manual control only. For instance, you can take user’s consent before moving away from a screen in the app.

  4. Hello, thanks for the nice article. It has some great lessons on using fragments in Android.

    I suspect the Back Stack Handling feature does not work as intendend. If I go two steps (from the “step 0” aka “Start ascending!” screen to the step 2 screen) and then go back one step it returns to the step 0 screen instead of the step 1 screen as it should. This is because two fragment replacements are being committed in a single transaction. If you commit one fragment replacement at a time the issue is fixed:

    @Override
    public void addMultipleFragments(BaseFragment[] fragments) {
    for(int i = 0 ; i < fragments.length ; i++) {
    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    ft.setCustomAnimations(R.anim.fragment_slide_in_left, R.anim.fragment_slide_out_left, R.anim.fragment_slide_in_right, R.anim.fragment_slide_out_right);
    ft.replace(R.id.home_frame_layout_for_fragments, fragments[i], fragments[i].getTagText());
    ft.addToBackStack(fragments[i].getTagText());
    ft.commit();
    }
    }

  5. Actually this is a better solution:

    @Override
    public void addMultipleFragments(BaseFragment[] fragments, boolean withAnimation) {
    for(int i = 0 ; i < fragments.length ; i++) {
    addFragment(fragments[i], withAnimation);
    }
    }

    Note however that the animations to-and-fro won't work well after screen rotations, because there is a bug in the fragment libraries which prevents animations to be persisted across configuration changes: https://code.google.com/p/android/issues/detail?id=25994).

    Also the Home.onCreate() method can benefit from the following change:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.home);

    drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    drawer.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);

    if (savedInstanceState == null) {
    openDrawer();
    showDrawerItemFragment(new GreetingsRequestFragment());
    }

    initUI();

    // Set up Facebook
    setUpFacebookInOnCreate(savedInstanceState);
    }

    This way the app will correctly persist the selected (current) fragment and drawer open/closed status across rotations. AndroidManifest.xml no longer needs the android:screenOrientation="portrait" restrictions and the device can be freely rotated.

  6. It’s as per expectation (as has been explained in the post). The terminology might be dubious and so could be its use case. The add-2-remove-2 scenario here is intended to make it clear that TransactionBackstack deals with ‘Transactions’ rather than ‘Fragments’.

    The current example doesn’t really make any sense. The second fragment gets to have no presence. That was just for demonstration. However, a transaction can have a mixture of operation-types. Such as, 1 add + 1 remove.

    A simple use case of adding-removing multiple fragments could be such as when you have a multi-pane tablet app, where you might require to add and remove fragments from multiple panes at the same time. Let me know if this is making things clear to you.

  7. Yes it is quite clear. There is no requirement that the relationship between fragments and transactions is one-to-one. But this leads me to a question: since we may tag transactions and a transaction tag should be unique in order to be properly popped, wouldn’t tagging a transaction after a fragment cause problems if the fragment is reused across the application in more than one place? Shouldn’t we consider a different scheme for tagging transactions uniquely?

Leave a Reply

Your email address will not be published. Required fields are marked *