In my travels through the world of Android I faced a lot of challenges. Brave as I am, *cough* I conquered each one of them. A few of the challenges include saving activity state, asynchronous tasks, pagination, error handling, context/option menu’s and even drawing custom application/tab icons in Photoshop! Some challenges I alreadyshared with you guys, but there is one challenge in particular I would like to elaborate on this time.

The app I am currently building is getting larger every day, and so is the main Activity class! Because my main activity contains a TabHost with a bunch of tabs, it also contains references to all individual view components contained in those tabs. All kinds of listeners are registered on those components so the activity contains some inner and anonymous classes as well. So you could say that this activity now has way too much responsibility! What I was looking for, is a way to separate the main activity into multiple parts, each with its own clear responsibility.

As it turns out, you can create custom components for a single piece of functionality within an Activity. Exactly what I was looking for!

Writing custom components

There are different ways to write custom components for your Android application.

Simply extend a view class – If you want to add some behavior to an existing view class (like a TextView or a ListView) you can simply extend the class and override any method you like.

Create an entirely customized component – Extend the View class and implement everything from scratch. Create listeners, properties, implement onMeasure() and onDraw(), etcetera. This might be useful if you want a very specific component and fine grained for your needs, for example a slider control.

Compound components

Unfortunately both of the above approaches are not what I was looking for in this case. I was looking for a way to simply group a bunch of view components in a separate class, also containing all related behavior logic. Luckily there is a way to do this! In the documentation they call it “compound components”, which is exactly what I was looking for. To explain it, I will try to demonstrate it with the following example:

Identify the components

The first thing to do is to identify the individual components you want to separate. In this case we can simply split this activity into three components, one for each tab. Of course, the Activity itself will still exist for obvious reasons (handling menu items, displaying dialogs, etc.). So in the end we’ll have a total of 4 classes.

Create new component classes

Second step is to create a new class for each component you want to create, which extends some layout class. In the case of this example those layout classes are RelativeLayout, LinearLayout and TableLayout (see above layout definition). Next, move all components contained in those layouts to the appropriate classes along with all related logic (listeners, etc.).

Classes called SecondTab and ThirdTab can be implemented in a similar way. First thing to notice about the above implementation is the constructor. It should always have the following 2 arguments: Context and AttributeSet. Without such a constructor this component can’t be instantiated from XML. Another thing to notice is that a layout called “firstTab” is inflated on instantiation. All instantiated views in that layout are added as a child of FirstTab

Now, let’s try to create the “firstTab” layout that is being instantiated from the FirstTab component class:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android">
<!-- All view components of the first tab -->
</LinearLayout>

There is a problem with this layout definition. If you think about it, you’ll notice what’s wrong with it. The problem is that when this layout is inflated, an instance of LinearLayout is created with all it’s defined child components attached. This is a problem because after the LinearLayout is instantiated, it is attached as a child component of the FirstTab, which itself already is a LinearLayout. So using this layout you will get a redundant LinearLayout in between the FirstTab and its child components.

The solution for this problem took me a while to figure out, but is actually quite simple. Instead of LinearLayout you should use the merge tag like this:

<merge xmlns:android="http://schemas.android.com/apk/res/android">
<!-- All view components of the first tab -->
</merge>

The merge tag makes sure that all its child views are attached to the merge tag’s parent instead. This is exactly what we want! Because now no new LinearLayout is instantiated and all child components are attached directly to the FirstTab.

To reference your new components from the original layout definition “main.xml”, you should use the fully qualified class name of the components. So this is how the layout could look like now:

This is it! Now you have divided your views over several components (classes).

Keep components loosely coupled

Now that you have all your view and behavior logic divided into multiple classes, you will probably run into some issues. Examples:

FirstTab wants to refresh the SecondTab after a click on certain button

Menu items are handled in MyActivity, but actually need to make changes to ThirdTab when selected

Listeners

The issue with the first example is, that FirstTab doesn’t have a reference to SecondTab to be able to refresh it. Under no circumstance should you give the FirstTab a direct reference to the SecondTab. This would result in very tight coupling between the components, which generally is not a good idea. Instead try to solve the issue using listeners. This is already a pattern implemented in a lot of places in the Android SDK itself, for example here: View#setOnClickListener(OnClickListener). So in the above example, you should create your own listener interface:

This could for example be a listener for when a search is performed in the FirstTab. The MyActivity class could register an anonymous implementation of this listener interface and call the SecondTab to refresh it.

So, create methods on your custom components if you need to control them from your Activity. Never expose any child components of your custom component to the Activity. The Activity should not have to know about them at all. Instead, create methods on your custom components that controls these child components like the above examples (refresh(…) and addEntry()).

I think with similar approaches, all issues can be solved when splitting your activity in multiple components. When you solve all issues you might have, you will have a cleanly separated Android application! This improves the overview of the application and makes it more maintainable.

Summary

I’ve shown you how to avoid making a mess of your application’s Activities by splitting clear chunks of functionality into custom components. Also, to avoid tight coupling between the custom components, I suggested to use Listeners.

If you have ever tried to deal with this before and have other suggestions to approach this, please leave a comment! Also, if you decided to try this structure in your application, let me know how that works out for you by leaving a comment!

9 Responses

Exactly what I was looking for, thank you very much.
I saw your question on StackOverflow, which was exactly the sort of thing I was after. Thanks for following it up with a blog post.

September 14, 2010 at 08:53by Zarah

|

Hi! Thanks for this! I am trying to create an app with a TabHost and I used to have Activities inside each tab, which according to a LOT of guys on StackOverflow is a no-no. Then I found this and tried your approach.

Looks pretty good! But somehow I can’t make it to work. I get the tabs, but the content are is blank. Would debug some more and let you know. (I would also accept suggestions!)

Thanks again!

September 14, 2010 at 09:04by Zarah

|

Oooops, maybe I spoke too soon. Found the problem with the empty tab contents, turned out it’s just from my layout. I wonder, if you have a button in one of your tab contents and you want to show a dialog onClick of that button, how do you tell your tab activity to show it?

Thanks again!

September 17, 2010 at 15:40by Martin

|

Very well written/explained – thanking you

But one question – say our composite control has a textview to display a caption – how do we use the attributes in the main.xml layout to pass a string value to be used as the caption?

December 10, 2010 at 16:45by GiUmaTo

|

Hi. Well done, good explanation. I saw your question on stackoverflow too … maybe it would be nice to cite the guy who answered :).
Anyway, probably there’s a typo in the code listing for ‘public class FirstTab': the constructor found afterwards is ‘public SecondTab(Context context…’, it should be for the same FirstTab.
Regards

December 24, 2010 at 16:21by Raja V

|

Great stuff.. After so many thought of doing this with inheriting the custom Activity, I found this tutorial as very simple and cool stuff… Thanks a lot..

January 11, 2011 at 22:33by Lamont

|

Great article! I think there is a small error in the code listing for FirstTab. The constructor is named SecondTab.

January 12, 2011 at 09:08by Tom van Zummeren

|

@Lamont You are totally right! Thank you.

March 5, 2012 at 15:24by sakis

|

amazing article!
I managed to get it working in minutes!
thanks a lot for your effort.

Trifork offices

Erlang Solutions offices

GOTO Chicago Register today!

Join us at GOTO Chicago: Conference: May 11-12 / Workshops May 13-14

The International software development conferences are designed for software developers, IT architects, product owners, agilists and project managers.As these are created “by developers, for developers” the emphasis is placed on presenting latest developments as they become relevant and interesting for the software development community.

Trifork Weliketoshare Community

At Trifork we are not only passionate about what we do we are also passionate about giving back. Social responsibility starts with us .. together we can make a difference.

Latest Tweets

Meta

About this blog

The content on this blog is developed mostly by our own developers. It contains a selection of best practices, trends and technical information on different open source technologies. Our blog is where we can share our experiences with technologies we are experimenting with, advancing with and more often than not indulging in.
In true open source community style, we don't hold back and we share code snippets, screen shots and provide insight wherever we can. We particularly enjoy setting up a dialogue with our readers and often there is also a thread of question and answers in the blogs too. Our blogs are not however all about just the technical successes but also our less successful efforts too ;-)

trifork

In many of our blogs, you'll find we endeavour to take you on a journey of our thought process. This means some of our blogs can often become epics and have a whole series associated with them.
We think that most of our readers appreciate reading about our experiences on new products, releases, conferences and technologies and to be honest its what makes us tick and what we thrive on most. Every now and then we also invite partners, industry leaders and others around us as guest writers or we share some interesting conversations we have had with them.
Suggestions, input and feedback is always welcome, just drop us a note and we'd be happy to hear from you.