Android Project Structure - Organizing your Source Files

Overview

Android applications should always be neatly organized with a clear folder structure that makes your code easy to read. In addition, proper naming conventions for code and classes are important to ensure your code is clean and maintainable.

Naming Conventions

Be sure to check out the Ribot Code and Style Guidelines for a more extensive breakdown of suggested style and naming guidelines.

For Java Code

The following naming and casing conventions are important for your Java code:
TypeExampleDescriptionLink
VariableincomeTaxRateAll variables should be camel caseRead More
ConstantDAYS_IN_WEEKAll constants should be all uppercaseRead More
MethodconvertToEuroDollarsAll methods should be camel caseRead More
ParameterdepositAmountAll parameter names should be camel caseRead More
See this naming guide for more details.

For Android Classes

Android classes should be named with a particular convention that makes their purpose clear in the name. For example all activities should end with Activity as in MoviesActivity. The following are the most important naming conventions:
NameConventionInherits
ActivityCreateTodoItemActivityAppCompatActivityActivity
List AdapterTodoItemsAdapterBaseAdapterArrayAdapter
Database HelperTodoItemsDbHelperSQLiteOpenHelper
Network ClientTodoItemsClientN/A
FragmentTodoItemDetailFragmentFragment
ServiceFetchTodoItemServiceServiceIntentService
Use your best judgement for other types of files. The goal is for any Android-specific classes to be identifiable by the suffix.

Android Folder Structure

There are several best practices for organizing your app's package structure.

Organize packages by category

The way to do this is to group things together by their category. Each component goes to the corresponding package:
  • com.example.myapp.activities - Contains all activities
  • com.example.myapp.adapters - Contains all custom adapters
  • com.example.myapp.models - Contains all our data models
  • com.example.myapp.network - Contains all networking code
  • com.example.myapp.fragments - Contains all fragments
  • com.example.myapp.utils - Contains all helpers supporting code.
  • com.example.myapp.interfaces - Contains all interfaces
Keeping these folders in each app means that code is logically organized and scanning the code is a pleasant experience. You can see a slight variation on this structure as suggested by Futurice on their best-practices repo.

Organize packages by application features

Alternatively, we can package-by-feature rather than layers. This approach uses packages to reflect the feature set. Consider the following package structure as outlined in this post:
  • com.example.myapp.service.* - Is a subpackage for all background related service packages/classes
  • com.example.myapp.ui.* - Is a subpackage for all UI-related packages/classes
  • com.example.myapp.ui.mainscreen - Contains classes related to some app's Main Screen
  • com.example.myapp.ui.detailsscreen - Contains classes related to some app's Item Details Screen
This feature allows you to place DetailsActivityDetailsFragmentDetailsListAdapterDetailsItemModel in one package, which provides comfortable navigation when you're working on "item details" feature.
DetailsListAdapter and DetailsItemModel classes and/or their properties can be made package-private, and thus not exposed outside of the package. Within the package you may access their properties directly without generating tons of boilerplate "setter" methods.
This can make object creation really simple and intuitive, while objects remain immutable outside the package.

Organizing Resources

Resources should be split up into the following key files and folders:
NamePathDescription
XML Layoutsres/layout/This is where we put our XML layout files.
XML Menusres/menu/This is where we put our AppBar menu actions.
Drawablesres/drawableThis is where we put images and XML drawables.
Colorsres/values/colors.xmlThis is where we put color definitions.
Dimensionsres/values/dimens.xmlThis is where we put dimension values.
Stringsres/values/strings.xmlThis is where we put strings.
Stylesres/values/styles.xmlThis is where we put style values.
See the full list of resources here and note the following:
  • Don't hardcode color hex values in the layout. Instead of hardcoding these values, be sure to move all colors into res/values/colors.xml and reference the colors in layouts with @color/royal_blue.
  • Don't hardcode margin / padding dimensions in the layout. Instead of hardcoding these values, be sure to move all dimension values into res/values/dimens.xml and reference these in layouts with @dimen/item_padding_left.
  • To support multiple devices, we can then use the alternative resources system to provide different colors, strings, dimens, styles, etc based on the device type, screen size, API version and much more.
Be sure to start properly organizing your resources early on in the development of an application. Be sure to check out the Ribot Code and Style Guidelines for a more extensive breakdown of suggested style and naming guidelines.

Organizing Resources into Subfolders

Often there are questions about organizing not just the source files but also better organizing the application resources. In a modern app, there are often hundreds of different layout files, drawables, styles, etc and by default these are all grouped together in a flat list within a single subdirectory (i.e res/layout). For now, keep the layout resource files in the same directory.
Refer to stackoverflow post for a discussion of explored options. The main problem is that if you try to use the nested resource layout approach, the current logic for the Android Studio's Gradle plug-in will not update the resource files after they have changed for nested resource sets. The current implementation attempts to check the resource directories using startsWith(), so a directory structure that is nested (i.e. src/main/res/layout/layouts and src/main/res/layout/layouts_category2) will choose src/main/res/layout/layouts consistently and never actually update the changes. A result, you will you have to rebuild/clean the project each time whenever making layout file changes.

Conclusion

It is up to you to decide which of the aforementioned approaches suits your project best.
However, in general Java programming, packaging apps by feature is considered preferable and makes a lot of sense.

References

Comments

Popular Posts