Skip to content
memo.d.foundation / about / playbooks / android-best-practices-app-structure-resourcesConnect

Playbooks/Product engineering

Best practices in Android development, part 2: app structure and resources

When to use activities or fragments, how to lay out Java packages, and how to keep layout XML, styles, colors and dimens organized.

Use with AI

This part covers how to shape the app itself: the choice between activities and fragments, a package layout, and the discipline for resources. Layout XML counts as code here, so the section on styles, colors and dimens is the longest. The guide dates from 2017 and Kotlin and Compose have since changed the picture; part 1 lists what has moved on.

Part 2 of 3 in the Android best practices series. Previous: Best practices in Android development, part 1: build setup and libraries | Next: Best practices in Android development, part 3: testing, ProGuard, storage and tooling

1Activities and fragments

There is no consensus among the community how to best organize Android architectures with Fragments and Activities. Square even has a library for building architectures mostly with Views, bypassing the need for Fragments, but this still is not considered a widely recommendable practice in the community.

Because of Android API's history, you can loosely consider Fragments as UI pieces of a screen. In other words, Fragments are normally related to UI. Activities can be loosely considered to be controllers, they are especially important for their lifecycle and for managing state. However, you are likely to see variation in these roles: activities might take UI roles (delivering transitions between screens), and fragments might be used solely as controllers. We suggest you sail carefully, making informed decisions since there are drawbacks for choosing a fragments-only architecture, or activities-only, or views-only. Here is some advice on what to be careful with, but take them with a grain of salt:

  • Avoid using nested fragments extensively, because matryoshka bugs can occur. Use nested fragments only when it makes sense (for instance, fragments in a horizontally-sliding ViewPager inside a screen-like fragment) or if it's a well-informed decision.
  • Avoid putting too much code in Activities. Whenever possible, keep them as lightweight containers, existing in your application primarily for the lifecycle and other important Android-interfacing APIs. Prefer single-fragment activities instead of plain activities - put UI code into the activity's fragment. This makes it reusable in case you need to change it to reside in a tabbed layout, or in a multi-fragment tablet screen. Avoid having an activity without a corresponding fragment, unless you are making an informed decision.

2Java packages structure

We recommend using a feature based package structure for your code. This has the following benefits:

  • Clearer feature dependency and interface boundaries.
  • Promotes encapsulation.
  • Easier to understand the components that define the feature.
  • Reduces risk of unknowingly modifying unrelated or shared code.
  • Simpler navigation: most related classes will be in the one package.
  • Easier to remove a feature.
  • Simplifies the transition to module based build structure (better build times and Instant Apps support)

The alternative approach of defining your packages by how a feature is built (by placing related Activities, Fragments, Adapters etc in separate packages) can lead to a fragmented code base with less implementation flexibility. Most importantly, it hinders your ability to comprehend your code base in terms of its primary role: to provide features for your app.

3Resources

Naming. Follow the convention of prefixing the type, as in type_foo_bar.xml. Examples: fragment_contact_details.xml, view_primary_button.xml, activity_main.xml.

Organizing layout XMLs. If you're unsure how to format a layout XML, the following convention may help.

  • One attribute per line, indented by 4 spaces
  • android:id as the first attribute always
  • android:layout_**** attributes at the top
  • style attribute at the bottom
  • Tag closer /> on its own line, to facilitate ordering and adding attributes.
  • Rather than hard coding android:text, consider using Designtime attributes available for Android Studio.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

    <TextView
        android:id="@+id/name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:text="@string/name"
        style="@style/FancyText"
        />

    <include layout="@layout/reusable_part" />

</LinearLayout>

As a rule of thumb, attributes android:layout_**** should be defined in the layout XML, while other attributes android:**** should stay in a style XML. This rule has exceptions, but in general works fine. The idea is to keep only layout (positioning, margin, sizing) and content attributes in the layout files, while keeping all appearance details (colors, padding, font) in styles files.

The exceptions are:

  • android:id should obviously be in the layout files
  • android:orientation for a LinearLayout normally makes more sense in layout files
  • android:text should be in layout files because it defines content
  • Sometimes it will make sense to make a generic style defining android:layout_width and android:layout_height but by default these should appear in the layout files

Use styles. Almost every project needs to properly use styles, because it is very common to have a repeated appearance for a view. At least you should have a common style for most text content in the application, for example:

<style name="ContentText">
    <item name="android:textSize">@dimen/font_normal</item>
    <item name="android:textColor">@color/basic_black</item>
</style>

Applied to TextViews:

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/price"
    style="@style/ContentText"
    />

You probably will need to do the same for buttons, but don't stop there yet. Go beyond and move a group of related and repeated android:**** attributes to a common style.

Split a large style file into other files. You don't need to have a single styles.xml file. Android SDK supports other files out of the box, there is nothing magical about the name styles, what matters are the XML tags <style> inside the file. Hence you can have files styles.xml, styles_home.xml, styles_item_details.xml, styles_forms.xml. Unlike resource directory names which carry some meaning for the build system, filenames in res/values can be arbitrary.

colors.xml is a color palette. There should be nothing in your colors.xml other than a mapping from a color name to an RGBA value. This helps avoid repeating RGBA values and as such will make it easy to change or refactor colors, and also will make it explicit how many different colors are being used. Normally for a aesthetic UI, it is important to reduce the variety of colors being used.

So, don't define your colors.xml like this:

<resources>
    <color name="button_foreground">#FFFFFF</color>
    <color name="button_background">#2A91BD</color>
</resources>

Instead, do this:

<resources>
    <!-- grayscale -->
    <color name="white">#FFFFFF</color>

    <!-- basic colors -->
    <color name="blue">#2A91BD</color>
</resources>

Ask the designer of the application for this palette. The names do not need to be plain color names as "green", "blue", etc. Names such as "brand_primary", "brand_secondary", "brand_negative" are totally acceptable as well.

By referencing the color palette from your styles allows you to abstract the underlying colors from their usage in the app, as per:

  • colors.xml - defines only the color palette.
  • styles.xml - defines styles which reference the color palette and reflects the color usage. (e.g. the button foreground is white).
  • activity_main.xml - references the appropriate style in styles.xml to color the button.

If needed, even further separation between underlying colors and style usage can be achieved by defined an additional color resource file which references the color palette. As per:

<color name="button_foreground">@color/white</color>
<color name="button_background">@color/blue</color>

Then in styles.xml:

<style name="AcceptButton">
    <item name="android:foreground">@color/button_foreground</item>
    <item name="android:background">@color/button_background</item>
</style>

This approach offers improved color refactoring and more stable style definitions when multiple related styles share similar color and usage properties. However, it comes at the cost of maintaining another set of color mappings.

Treat dimens.xml like colors.xml. You should also define a "palette" of typical spacing and font sizes, for basically the same purposes as for colors. A good example of a dimens file:

<resources>

    <!-- font sizes -->
    <dimen name="font_larger">22sp</dimen>
    <dimen name="font_large">18sp</dimen>
    <dimen name="font_normal">15sp</dimen>
    <dimen name="font_small">12sp</dimen>

    <!-- typical spacing between two views -->
    <dimen name="spacing_huge">40dp</dimen>
    <dimen name="spacing_large">24dp</dimen>
    <dimen name="spacing_normal">14dp</dimen>
    <dimen name="spacing_small">10dp</dimen>
    <dimen name="spacing_tiny">4dp</dimen>

    <!-- typical sizes of views -->
    <dimen name="button_height_tall">60dp</dimen>
    <dimen name="button_height_normal">40dp</dimen>
    <dimen name="button_height_short">32dp</dimen>

</resources>

You should use the spacing_**** dimensions for layouting, in margins and paddings, instead of hard-coded values, much like strings are normally treated. This will give a consistent look-and-feel, while making it easier to organize and change styles and layouts.

strings.xml

Name your strings with keys that resemble namespaces, and don't be afraid of repeating a value for two or more keys. Languages are complex, so namespaces are necessary to bring context and break ambiguity.

Bad

<string name="network_error">Network error</string>
<string name="call_failed">Call failed</string>
<string name="map_failed">Map loading failed</string>

Good

<string name="error_message_network">Network error</string>
<string name="error_message_call">Call failed</string>
<string name="error_message_map">Map loading failed</string>

Don't write string values in all uppercase. Stick to normal text conventions (e.g., capitalize first character). If you need to display the string in all caps, then do that using for instance the attribute textAllCaps on a TextView.

Bad

<string name="error_message_call">CALL FAILED</string>

Good

<string name="error_message_call">Call failed</string>

Avoid a deep hierarchy of views. Sometimes you might be tempted to just add yet another LinearLayout, to be able to accomplish an arrangement of views. This kind of situation may occur:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

    <RelativeLayout
        ...
        >

        <LinearLayout
            ...
            >

            <LinearLayout
                ...
                >

                <LinearLayout
                    ...
                    >
                </LinearLayout>

            </LinearLayout>

        </LinearLayout>

    </RelativeLayout>

</LinearLayout>

Even if you don't witness this explicitly in a layout file, it might end up happening if you are inflating (in Java) views into other views.

A couple of problems may occur. You might experience performance problems, because there is a complex UI tree that the processor needs to handle. Another more serious issue is a possibility of StackOverflowError.

Therefore, try to keep your views hierarchy as flat as possible: learn how to use ConstraintLayout, how to optimize your layouts and to use the <merge> tag.

Beware of problems related to WebViews. When you must display a web page, for instance for a news article, avoid doing client-side processing to clean the HTML, rather ask for a "pure" HTML from the backend programmers. WebViews can also leak memory when they keep a reference to their Activity, instead of being bound to the ApplicationContext. Avoid using a WebView for simple texts or buttons, prefer the platform's widgets.