Bei der Entwicklung von Anwendungen für das Android OS kommt es vor, dass allgemeine Activities oder Services mit wenig Änderungen in weiteren Anwendungen wieder verwendet werden könnten. Da Sie diese Klassen nicht in jedes einzelnen Projekt kopieren möchten – was zu einem kaum handhabbarem Code führen würde – wäre es besser, einen Weg zu finden, den Quellcode dieser Klassen aus weiteren Projekten heraus zu referenzieren. Für Nicht-Android-Anwendungen kann man das Problem lösen, indem man den Code in mehrere Bibliotheken aufteilt, so dass die gewünschte Funktionalität von mehreren Projekten referenziert werden kann. Solange keine Interaktion mit externen Ressourcen nötig ist, ist das auch in Android Projekten ohne weiteres möglich (erstellen Sie ein jar und referenzieren Sie es in den Projekten). Aber wenn Sie mit externen Ressourcen arbeiten, können diese Klassen nicht innerhalb einer Bibliothek verwendet werden, weil das Android SDK keine passenden IDs innerhalb der “R”-Klasse für externe Ressourcen erzeugt, die in einer referenzierten jar-Datei enthalten sind.

In diesem Beitrag möchte ich Ihnen verschiedene Lösungen für dieses Problem zeigen, wodurch Sie vermeiden können, den Quellcode in die Projekte zu kopieren.

Sie können den Quellcode der Beispielprojekte in unserem SVN-Repository auf Google Code (http://code.google.com/p/android-using-activities-services-in-multiple-projects-example/) anschauen oder herunterladen; oder verwenden Sie svn, um das Projekt auszuchecken.

Referenzierung von Layout Ressourcen

Bei Activities ist das Layout eines der wichtigsten Probleme, die ihnen begegnen werden. Typischerweise ist das Layout in einer XML-Layout-Ressource Datei definiert, wo einzelne Elemente anhand ihrer ID identifiziert werden können.

Um Activities in mehreren Projekten zu verwenden, habe ich zwei mögliche Lösungen gefunden, die die Wiederverwendung von Activities ermöglicht, ohne die Quelldatei in die Projekte zu kopieren oder sich auf ein auf dem Handy installiertes basis apk package verlassen zu müssen.

Statisches Layout

Dieser Ansatz basiert auf einer XML-Layout-Datei. Die Layout-Datei muss in den Projekten zur Verfügung gestellt werden, in denen die Activity referenziert wird, so dass doch noch etwas Kopieren nötig ist. Aber zumindest ist es möglich, die Business-Logik im Quellcode ohne direktes Kopieren zu referenzieren. Die Idee hinter dieser Lösung ist, dass man eine abstrakte Activity mit get-Methoden für die Ressourcen-IDs bereitstellt. Anstelle der Verwendung der R.id. * Felder bei der Arbeit mit dem Layout und den View-Elementen, nehmen Sie diese Getter, um die Elemente zu identifizieren. Im mitgelieferten Beispiel-Quellcode wird dies in der BaseAppWithXMLLayoutActivity Klasse durchgeführt. Die Activity benutzt ein EditText Feld, einen Button und das Layout. Für diese drei Elemente sind abstrakte Getter vorgesehen:

protected abstract int getLayoutId();

protected abstract int getEditTextId();

protected abstract int getButtonId();

Während des onCreate Aufrufs werden diese Methoden benutzt, um die View Elemente zu erhalten:

@Override
public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(getLayoutId());

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

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

…

}

Wenn Sie diese Activity zu einem Projekt hinzufügen wollen, müssen Sie eine Layout-Datei bereit stellen und eine Unterklasse der Klasse BaseAppWithXMLLayoutActivity erzeugen. In dem Beispiel stelle ich die layout_for_baseapp_with_xml_layout.xml Layout-Datei zur Verfügung:



    
    

Diese IDs können nun in der MyFinalXMLLayoutActivity Klasse benutzt werden, um die abstrakten Methoden zu implementieren:

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;

    }

}

Die MyFinalXMLLayoutActivity Activity kann jetzt zur Manifest-Datei hinzugefügt und innerhalb des Projekts benutzt werden.

Ein Nachteil dieses Ansatzes ist die Notwendigkeit, die XML-Layout-Datei in das fertige Projekt zu kopieren. Aber in einigen Fällen könnte dies sogar ein Vorteil sein, weil die abstrakte Activity Klasse für einen bestimmten Zweck entwickelt wird, und so lange die View-Elemente in den Projekten, die diese Activity nutzen, die gleichen sind, kann das Layout in jedem Projekt unterschiedlich sein, ohne die Funktionalität jedes Mal neu zu implementieren.

Dynamisches Layout

Bei Verwendung eines dynamisch erstellten Layouts gibt es keine Ressourcen-IDs, auf die während der Erstellung des Content View verwiesen wird. Die BaseAppWithDynamicLayoutActivity Activity demonstriert diesen Ansatz. Während des OnCreate Methodenaufrufs wird die View programmatisch erzeugt:

@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));

    …

}

Wie Sie sehen, wird die Android “R”-Klasse nicht verwendet, um Ressourcen zu identifizieren. Mit diesem Ansatz ist es nicht erforderlich, die Activity abstrakt zu machen, allerdings ist das Layout hart codiert und kann daher nicht für einzelne Projekte angepasst werden.

Referenzierung von zusätzliche Ressourcen (Strings, Drawables,..)

Wenn Sie zusätzliche Ressourcen in der Activity oder der Service Klasse referenzieren wollen, müssen diese Ressourcen in das Projekt kopiert werden, in dem die Bibliothek verwendet wird. Darüber hinaus – wie im “Statisches Layout” Kapitel gezeigt wurde – müssen abstrakte Getter-Methoden für die Ressourcen-IDs in der Klasse zur Verfügung gestellt werden. Dies wird in der BaseAppWithDynamicLayoutActivity Activity gezeigt, in der eine modifizierte Toast Nachricht erstellt wird, die ein Icon und einen Text anzeigt. Zu diesem Zweck werden zwei abstrakte Methoden eingeführt, die die entsprechenden IDs zurückgeben:

protected abstract int getMessageId();

protected abstract int getMessageImageId();

Bei der Erstellung des Toast werden diese Getter-Methoden verwendet, um die Text Ressource und die Bild Ressource eines TextView und eines ImageView Elements zu setzen:

ImageView imageView = new ImageView(context);

TextView textView = new TextView(context);

imageView.setImageResource(getMessageImageId());

textView.setText(getMessageId());

Zusammenfassung

Die vorgeschlagenen Lösungen haben alle Ihre Nachteile. Aber wenn die GUI, die von Ihrer Activity bereit gestellt wird, oder Ihr Service Business-Logik enthält, die externe Ressourcen erfordert, sind sie eine gute Möglichkeit, die Wiederverwendbarkeit von Code in anderen Projekten zu erhöhen.

Übersetzung: Ralf Wienken