Using Android Activities and Services in multiple Projects

When developing Apps for the Android OS you might end up in the situation where you have common Activities or Services which could be reused in multiple Apps with just a little modification. As you don’t want to copy these classes into every single project – which would lead to a hardly maintainable code – you would seek a way to reference the source of these classes from multiple projects. For non-android applications an approach for this problem would be to break up the code into multiple libraries so that the required functionality can be referenced from multiple projects. As long as you are not interacting with external resources this attempt is also possible in Android projects (build a jar and reference it from the projects). But if you are using external resources these classes can’t be used within a library. This is caused by the fact that the Android SDK won’t generate matching ids within the “R” class for external resources which are included in a referenced jar file. In this post I want to show you different solutions for this problem which can avoid the necessity to copy the source code into the projects.
You can browse or download the source code of the example projects at our SVN repository at Google Code (http://code.google.com/p/android-using-activities-services-in-multiple-projects-example/) or use svn to check the project out.

Referencing Layout Resources

For Activities one of the main problems you will face is the layout. Typically the layout is defined in an external layout xml resource file where single elements can be identified by their id. To include Activities in multiple projects I’ve identified two possible solutions which will enable the reuse of activities in multiple projects without the need to copy the source file into multiple projects or relying on an installed base apk package on the phone.

Static Layout

This approach is still relying on a XML layout file. This layout file has to be provided in the projects where the Activity is referenced so there is still some copying left. But at least it’s possible to reference the business logic in the source code without directly copying this code. The idea behind this solution is that you provide an abstract Activity with get-Methods for the resource ids. Instead of using the R.id.* fields when working with the layout and view elements you use these getters to identify the elements. In the provided example source code this is done in the BaseAppWithXMLLayoutActivity class. This activity is using an EditText field, a Button and the Layout. For these three elements abstract getters are provided:

protected abstract int getLayoutId();

protected abstract int getEditTextId();

protected abstract int getButtonId();

During the onCreate call these methods are used to get the view elements:

@Override
public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(getLayoutId());

final EditText editText = (EditText)findViewById(getEditTextId());

Button button = (Button)findViewById(getButtonId());

…

}

When you want to add this activity to a project you have to provide a layout file and subclass the BaseAppWithXMLLayoutActivity class. In the example I provide the layout_for_baseapp_with_xml_layout.xml layout file:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent">
<EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/baseAppEditText" android:text="@string/helloWorld" />
<Button android:text="@string/buttonText" android:id="@+id/baseAppButton" android:layout_width="fill_parent" android:layout_height="wrap_content" />
</LinearLayout>

These ids can then be used in the MyFinalXMLLayoutActivity class to implement the abstract methods:

public class MyFinalXMLLayoutActivity extends BaseAppWithXMLLayoutActivity {

@Override
protected int getButtonId() {

return R.id.baseAppButton;

}

@Override

protected int getEditTextId() {

return R.id.baseAppEditText;

}

@Override

protected int getLayoutId() {

return R.layout.layout_for_baseapp_with_xml_layout;

}

}

The MyFinalXMLLayoutActivity activity can now be added to the manifest file and used inside the project.

One drawback of this approach is the need to copy the xml layout file to the final project. But in some cases this might be even an advantage because the abstract Activity class will be developed for a certain purpose and as long as the view elements in the projects which will use this Activity are the same the layout can be individual in every project without re-implementing the functionality every time.

Dynamic Layout

When using a dynamically created layout, there are no resource ids which will be referenced during the creation of the content view. The BaseAppWithDynamicLayoutActivity is demonstrating this approach. During the onCreate method call the content view is generated programmatically:

@Override
public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

LinearLayout layout = new LinearLayout(this);

Button performAction = new Button(this);

performAction.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));

…

}

As you can see the android “R” class is not used to identify resources. Using this approach there is no need to make the Activity abstract but the layout is also hard coded and cannot be adjusted in individual projects.

Referencing Additional Resources (Strings, Drawables,..)

If you want to reference additional resources in the Activity or Service class these resources have to be copied to the project where the library is used. Additionally as demonstrated in the “Static Layout” section abstract getter methods for the resource ids have to be provided in the class. This is demonstrated in the BaseAppWithDynamicLayoutActivity where a custom Toast message is created which displays an icon and a text. For this purpose two abstract methods are introduced which will return the corresponding ids:

protected abstract int getMessageId();

protected abstract int getMessageImageId();

When creating the Toast these getter methods are used to set the text resource and the image resource of a TextView and ImageView element:

ImageView imageView = new ImageView(context);

TextView textView = new TextView(context);

imageView.setImageResource(getMessageImageId());

textView.setText(getMessageId());

Summary

The proposed solutions all have their drawbacks but if the GUI provided by your Activity or a Service contains business logic which requires external resources this can be a good way to increase the reusability of your code in other projects.

by Kevin Kratzer

Tags: , , , , , , , , , ,

Comments are closed.