Android_Tutorial_Lektion31_fotolia_RA_Studio_46292813

Programmier Tutorial: Apps für Android entwickeln – Teil 31: Mit einem impliziten Intent eine Activity in Android starten

In dieser Lektion werden wir eine App-fremde Activity mit Hilfe eines impliziten Intents vom Android System starten lassen. Die fremde Activity werden wir zum Nachschlagen der Zitat-Autoren auf der freien Enzyklopädie Wikipedia nutzen. Das Starten der Activity wird über die App Bar der DetailActivity erfolgen.

Diesmal werden wir zum Starten der Activity aber nicht ihren Namen explizit angeben, sondern die von ihr auszuführende Aufgabe mit Hilfe der Action-, Data– und Category-Felder im Intent-Objekt exakt beschreiben.


Das Android System kann anhand dieser Informationen die zur angeforderten Aufgaben passende Activity finden und für uns ausführen. Wie dies mit Hilfe des impliziten Intents in Android realisiert wird, werden wir ausführlich im theoretische Teil dieser Lektion beschreiben. Wir werden erfahren aus welchen Komponenten ein impliziter Intent besteht, was Intent Filter sind und wie das Android System die zum Intent passende Activity auswählt.

Anschließend werden wir im praktischen Teil dieser Lektion ein Menü für die App Bar der DetailActivity implementieren, über das die App-fremde Activity gestartet werden kann. Dazu werden wir neue String-Ressourcen und eine weitere XML-Menüdatei, mit den beiden Aktionen Autor nachschlagen und Einstellungen, unserem Android Projekt hinzufügen.

Mit Hilfe der neu erstellten Menüdatei werden wir dann das Options Menu der DetailActivity aktivieren und die darin definierten Menüeinträge als Aktionen im Overflow Menu der App Bar anzeigen lassen. Danach werden wir die Auswertungslogik der Aktionen implementieren. Die Autor nachschlagen-Aktion wird den impliziten Intent erzeugen und das Starten der App-fremden Activity veranlassen.

Abschließend werden wir unsere Android App im Emulator auf einem Android Virtual Device ausführen und prüfen, ob das Android System die zur angeforderten Aufgabe passende Activity per impliziten Intent startet und ob diese die ihr übertragene Aufgabe zufriedenstellend ausführt.

1. Implizite Intents in Android

Was Intents sind und wofür sie in Android eingesetzt werden, haben wir bereits in der vorherigen Lektion erfahren, in der wir mit Hilfe eines expliziten Intents eine bestimmte Activity unserer App gestartet haben. Diesmal möchten wir jedoch eine Activity einer anderen, auf dem Android Gerät installierten, App starten.

Da wir weder die anderen auf dem Android Gerät installierten Apps noch deren Activities zum Ausführungszeitpunkt unserer App kennen, können wir für dieses Vorhaben keinen expliziten Intent verwenden. Das Android System stellt uns jedoch eine Lösung für dieses Problem bereit: implizite Intents.

Ein impliziter Intent ist eine Art Benachrichtigungsobjekt, welches das Android System über ein bestimmtes Vorhaben (die Absicht etwas bestimmtes tun zu wollen) informiert. Mit einem impliziten Intent lässt man die eigene App beim Android System eine bestimmte Aktion anfragen, die nicht von einer App-eigenen sondern einer App-fremden Komponente, meist eine Activity, durchgeführt werden soll.

In unserem Fall möchten wir als Aktion weitere Informationen zu einem bestimmten Autor auf der freien Enzyklopädie Wikipedia nachschlagen lassen. Die Aktion soll von einer Web-App, wie Google Chrome, ausgeführt werden. Da wir nicht wissen welche Web-Apps auf dem jeweiligen Android Gerät installiert sind, stellen wir beim Android System nur die Anfrage (Request) diese bestimmte Aktion ausführen zu wollen.

Das Android System prüft dann, ob eine passende Web-App installiert ist und übergibt dieser die notwendigen Informationen, die benötigt werden um unsere angefragte Aktion auszuführen. Wie dies geschieht, besprechen wir im nächsten Abschnitt.

1.1 Wie implizite Intents vom Android System aufgelöst werden

Expliziten Intents haben wir bereits in der vorherigen Lektion kennengelernt. Durch sie wird die zu startende Komponente, Activity, Service oder Broadcast, durch exakte Angabe des Klassennamens vorgegeben. Sie werden typischerweise verwendet, um eine Komponente der eigenen App zu starten. Da man die Klassennamen der eigenen App-Komponenten kennt, ist das Verwenden expliziter Intents hierfür die richtige Wahl.

Wenn man mit einem expliziten Intent eine Activity oder einen Service startet, wird das Android System die vom Intent-Objekt mittels Klassennamen genannte App-Komponente sofort starten.

Implizite Intents legen keine bestimmte App-Komponente fest, die gestartet werden soll. Sie geben stattdessen eine allgemeine Aktion an, die von einer Komponente einer App ausgeführt werden soll. Möchte man bspw. dem Benutzer der eigenen App einen Standort auf einer Karte anzeigen, kann man mit einem impliziten Intent bei anderen Apps, die diese Funktionalität besitzen, anfragen diese Aktion auszuführen und zu übernehmen.

Bei einem impliziten Intent ist die zu startende App-Komponente nicht explizit genannt. Sie muss daher erst vom Android System gefunden werden. Das Android System findet die passende App-Komponente, indem es den Inhalt des impliziten Intents mit den Intent Filtern der anderen installierten Apps vergleicht. Die Intent Filter sind in der Manifest-Datei jeder App definiert.

Wenn ein impliziter Intent zu einem Intent Filter passt, startet das Android System die entsprechende App-Komponente und übergibt ihr das Intent-Objekt. Falls mehrere Intent Filter zum impliziten Intent passen, zeigt das Android System einen Auswahldialog an und der Benutzer kann die auszuführende App selbst auswählen.

In der unteren Abbildung ist dieser Prozess dargestellt:

android_implizit_intent

Wie ein impliziter Intent vom Android System zum Starten einer anderen Activity aufgelöst wird

Der implizite Intent wird von dem Android System empfangen und weiterverarbeitet und zwar folgendermaßen:

  1. Erzeugen des impliziten Intents – Die Activity A erzeugt einen impliziten Intent mit einer Beschreibung der auszuführenden Aktion und gibt den Intent an die startActivity() Methode weiter.

  2. Durchsuchen der Intent Filter – Das Android System durchsucht alle auf dem Gerät installierten Apps nach Intent Filtern. Dabei wird der Inhalt des Intent-Objekts mit den Intent Filtern der anderen auf dem Android Gerät installierten Apps verglichen. Jede installierte App gibt dazu in ihrem App Manifest ihre Intent Filter bekannt.

  3. Starten der passenden Activity – Falls der Intent mit einem Intent Filter übereinstimmt, startet das Android System durch Aufruf der onCreate() Methode diese App-Komponente (hier Activity B) und übergibt ihr das Intent-Objekt. Falls mehrere Intent Filter kompatibel sind, lässt das Android System einen Auswahldialog einblenden, durch den der Benutzer festlegen kann, welche App für das Ausführen der Aufgabe zu verwenden ist.

1.2 Was ist ein Intent Filter in Android

Ein Intent Filter ist ein Ausdruck in dem App Manifest, der AndroidManifest.xml Datei, einer Android App. Die Anwendung gibt mit ihren Intent Filtern dem Android System die impliziten Intents bekannt, die ihre eigenen Komponenten empfangen können. Sie bewirbt mit ihnen ihre Fähigkeiten beim System.

Jedes <intent filter> Element im App Manifest spezifiziert dabei durch Vorgaben der Intent-Eigenschaften action, data und category welche impliziten Intents von der jeweiligen App-Komponente akzeptiert werden. Das Android System liefert nur die impliziten Intents an die App-Komponente aus, die durch die jeweils angegebenen Intent Filter passen.

Hinweis: Ist kein Intent Filter für eine App-Komponente definiert, kann die Komponente nur mit einem expliziten Intent durch exakte Angabe des Klassennamens gestartet werden. Dabei wir der explizite Intent in jedem Fall vom Android System an die App-Komponente geliefert. Die definierten Intent Filter werden von expliziten Intents ignoriert.

Ein Beispiel für einen Intent Filter ist im unteren Quellcode angegeben:

<activity android:name=".ShareActivity">
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain"/>
    </intent-filter>
</activity>

Mit dem oberen Quellcode wird eine Activity mit einem Intent Filter deklariert. Durch ihren Intent Filter zeigt die Activity dem Android System an, dass sie nur ACTION_SEND-Intents empfangen kann, die als data type normalen Text (text/plain) enthalten.

Die <intent filter> Elemente müssen sich innerhalb der <activity> Elemente des App Manifests befinden. In den <intent filter> Elementen wird die Art des akzeptierten Intent-Objekts mit Hilfe der folgenden drei Elemente definiert werden:

  • <action> – Das <action> Element gibt an, welche Aktionen die App-Komponente ausführen kann. Bekannte Aktionen sind android.intent.action.SEND für das Versenden und android.intent.action.VIEW für das Betrachten eines beliebigen Inhalts. Die akzeptierte Aktion muss in dem android:name Attribut spezifiziert werden.

  • <data> – Das <data> Element gibt an, welche Art von Daten die App-Komponente empfangen und verarbeiten kann. Die Art der Daten kann mit Hilfe von verschiedenen Attributen wie android:scheme=“http“, android:host=“www.codeyourapp.de“ oder android:mimeType=“text/plain“ exakt beschrieben werden.

  • <category> – Das <category> Element gibt an, welche Kategorie das Intent-Objekt besitzen muss, um von der App-Komponente empfangen werden zu können. Mit der Intent-Kategorie android.intent.category.LAUNCHER wird die App-Komponente festgelegt, die geöffnet werden soll, wenn der Benutzer die App über das Launcher-Symbol startet.

    Hinweis: Damit die App-Komponente überhaupt implizite Intents empfangen kann, muss in ihrem Intent Filter als Intent-Kategorie android.intent.category.CATEGORY_DEFAULT angegeben werden. Falls dies nicht im Intent Filter angegeben wurde, werden keine impliziten Intents vom Android System an die App-Komponente aufgelöst. Neben dieser Default-Kategorie können weitere Kategorien angegeben werden, um die Fähigkeiten der App-Komponenten genauer zu spezifizieren.

    Weitere bekannte Intent-Kategorien sind android.intent.category.OPENABLE, die angibt, dass das von der App-Komponente zurückgelieferte Objekt von einem Content Provider geöffnet werde kann, und android.intent.category.BROWSABLE, die angibt, dass die App-Komponente Links von einer Webseite empfangen kann.

Wenn das Android System einen impliziten Intent zum Starten einer Activity von den Methoden startActivity() und startActivityForResult() erhält, sucht es nach der am besten passenden Activity zu der vom Intent-Objekt beschriebenen Aufgabe. Dabei vergleicht das Android System die Intent Filter nach ihren Eigenschaften action, data und category.

1.3 Aufbau eines impliziten Intents in Android

Ein Intent-Objekt enthält Informationen, die das Android System benutzt, um die App-Komponente zu bestimmen, die gestartet werden soll. Neben diesen Informationen enthält das Intent-Objekt zusätzliche Informationen, die von der empfangenen App-Komponente genutzt werden, um die gewünschte Aktion ausführen zu können.

Jedes Intent-Objekt enthält einige der folgenden Informationen:

  • Component Name – Über das Component Name-Feld wird dem Intent-Objekt mitgeteilt welche App-Komponente gestartet werden soll. Diese Angabe ist zwar optional, jedoch von entscheidender Bedeutung für den Intent. Denn durch Angabe des Component Name wird der Intent zu einem expliziten Intent, mit der Konsequenz, dass der Intent nur an die App-Komponente ausgeliefert wird, deren vollqualifizierender Name dem Component Name entspricht.

    Ohne Angabe des Component Name bleibt der Intent implizit und das Android System entscheidet welche App-Komponente den Intent erhalten soll. Dies geschieht auf Grundlage der anderen Intent-Informationen wie action, data und category. Daher sollte immer der Component Name angegeben werden, wenn eine bestimmte App-Komponente der eigenen Anwendung per Intent aufgerufen werden soll.

    Der Component Name kann dem Intent auf zwei Wege zugewiesen werden. Entweder mit Hilfe des Konstruktors direkt beim Erzeugen der Intent-Instanz oder über eine der folgenden Methoden setComponent(), setClass() oder setClassName(), die auf dem Intent-Objekt aufgerufen werden. In dem Component Name-Feld des Intents wird dann ein ComponentName-Objekt abgelegt, das den vollqualifizierenden Namen der Klasse der aufzurufenden App-Komponenten und den Package-Namen der App enthält.

  • Action – Über das Action-Feld wird dem Intent-Objekt mitgeteilt welche allgemeine Aktion von der zu startenden App-Komponente ausgeführt werden soll. Durch die Aktion wird die Struktur der weiteren im Intent enthaltenen Informationen maßgeblich beeinflusst. Die Inhalte der beiden Intent-Felder Data und Extra sind von der spezifizierten Aktion besonders stark vorbestimmt.

    Im Android System sind bereits viele allgemeine Aktionen in Form von Action-Konstanten in der Intent-Klasse und anderen Framework-Klassen vordefiniert. Diese Konstanten können zum Spezifizieren der Intent-Action genutzt werden. Bekannte solcher Action-Konstanten sind die ACTION_VIEW-Konstante zum Anzeigen eines Bildern in einer Galerie-App oder einer Adresse in einer Karten-App oder die ACTION_SEND-Konstante zum Teilen von Daten mit einer Share-App.

    Mit Hilfe der setAction() Methode wird eine Aktion für das Intent-Objekt spezifiziert. Es ist sogar möglich eine eigene Aktion für den Intent zu definieren. Diese müssen dann den Package-Namen als Präfix enthalten, um garantiert einzigartig zu sein:

    public static final String ACTION_READ_QUOTE = "de.codeyourapp.zitate.ACTION_READ_QUOTE";

  • Data – Das Data-Feld des Intent-Objekts enthält Informationen über die zu verarbeitenden Daten. Mit Hilfe einer URI (Uniform Resource Identifier) kann auf die Daten referenziert und/oder durch einen MIME type (Multipurpose Internet Mail Extensions) ihr Datentyp vorgegeben werden. Die Art der mitgelieferten Daten wird meist von der Action des Intents vorgegeben. So benötigt ein ACTION_EDIT-Intent als Data die URI, die auf das zu editierende Dokument verweist.

    Wenn ein impliziter Intent erstellt wird, ist es oft wichtig, zusätzlich zu seiner URI den Datentyp (MIME type) mit anzugeben. Eine Activity die Bilder anzeigen kann, könnte das gleiche URI-Format verwenden, wie eine Activity die Videos abspielen kann. Damit das Android System unterscheiden kann, welche der beiden Activities für das Anzeigen der Bilder zu verwenden ist, muss zur URI noch zusätzlich der MIME type Ihrer Daten mit angeben werden.

    Mit Hilfe der setData() Methode wird die URI zu den Intent-Daten spezifiziert. Mit der setType() Methode wird der MIME type der Intent-Daten vorgegeben. Um beide, die URI und den MIME type zu setzen, muss die setDataAndType() Methode verwendet werden, da die Methoden setData() und setType() jeweils den anderen Wert auf null setzen.

  • Category – In dem Category-Feld des Intent-Objekts werden zusätzliche Informationen über die Art der Komponente angegeben, welche den Intent verarbeiten soll. Es können mehrere Categories für einen Intent angegeben werden. Jedoch benötigen die meisten Intents keine Angabe der Category.

    Mit Hilfe der addCategory() Methode können Kategorien dem Intent-Objekt hinzugefügt werden. Die Kategorie android.intent.category.BROWSABLE besitzen nur Activities, die sicher von einem Browser aufgerufen werden können, um bspw. einen Textlink weiterzuverarbeiten.

    Jedem Intent-Objekt wird standardmäßig die Category android.intent.category.DEFAULT vom Android System zugewiesen. Daher muss in dem Intent Filter einer Activity immer auch die DEFAULT-Kategorie deklariert werden, wenn die Activity in der Lage sein soll Intents überhaupt empfangen zu können.

Die oben aufgeführten Eigenschaften (Component Name, Action, Data und Category) repräsentieren die Hauptmerkmale eines Intents. Das Android System kann durch Auswerten dieser Eigenschaften erkennen, welche App-Komponente durch den Intent gestartet werden soll.

Ein Intent-Objekt kann aber auch noch weitere zusätzliche Informationen beinhalten, die jedoch das Auflösen, welche App-Komponente gestartet werden soll, nicht beeinflussen.

Zusätzliche Intent-Informationen sind:

  • Extras – In das Extras-Feld können Schlüssel-Wert Paare (key-value pairs) abgelegt werden, die für die Ausführung der angeforderten Aufgabe benötigt werden. Die zusätzlichen Daten können mit Hilfe von verschiedenen putExtra() Methoden in das Intent-Objekt eingefügt werden. Jede dieser Methoden erwartet zwei Parameter: den Schlüssel und den dazugehörigen Wert. Es ist auch möglich alle Schlüssel-Wert Paare vorher in einem Bundle-Objekt zu speichern und dieses anschließend in das Intent-Objekt mittels der putExtra() Methode einzufügen.

    Von der Intent-Klasse werden bereits viele EXTRA_* Konstanten definiert. Diese können als Schlüssel zum Hinterlegen oft verwendeter Werte genutzt werden. So kann bspw. für den Schlüssel EXTRA_EMAIL die E-Mail Adresse oder für EXTRA_SUBJECT der E-Mail Betreff hinterlegt werden. Um Werte in das Extras-Feld abzuspeichern, können aber auch eigene Schlüssel verwendet werden. Diese müssen dann den Package-Namen als Präfix enthalten:

    public static final String EXTRA_QUOTE_TEXT = "de.codeyourapp.zitate.EXTRA_QUOTE_TEXT";

  • Flags – In das Flags-Feld des Intent-Objekts können Metadaten abgelegt werden. Mit Hilfe der Metadaten kann das Android System informiert werden, wie es die App-Komponente starten soll (z.B. unter welchem Task die gestartete Activity ausgeführt werden soll) oder wie eine Activity behandelt werden soll, nachdem sie gestartet wurde (z.B. ob sie in der Liste der Recent Activities aufgenommen werden soll). Die dafür erforderlichen Flags können mit Hilfe der setFlags() und addFlags() Methoden dem Intent-Objekt hinzugefügt werden.

1.4 Starten einer App-fremden Activity per impliziten Intent

Um eine App-fremde Activity von der eigenen Android App heraus zu startet, wird eine impliziter Intent benötigt. Möchte man bspw. dem Benutzer ermöglichen einen bestimmten Inhalt mit anderen zu teilen, so muss dafür keine eigene Activity implementiert werden. Stattdessen kann ein impliziter Intent mit einer ACTION_SEND-Aktion erzeugt werden, mit dessen Hilfe eine passende Activity einer anderen App aufgerufen wird, die dann das Teilen des Inhalts für uns übernimmt.

Das folgende Code-Beispiel zeigt, wie ein solcher impliziter Intent erzeugt und zum Aufrufen der passenden Activity an das Android System übergeben wird:

Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, "Dieser Text soll geteilt werden.");
sendIntent.setType("text/plain"); // Vorgabe des MIME type

// Sicherstellen, dass für den Intent eine Activity gefunden wurde
if (sendIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(sendIntent);
}

In den Zeilen 1 bis 4 wird ein impliziter Intent erzeugt. Dem Intent-Objekt wird über die setAction() Methode eine Intent.ACTION_SEND-Aktion zugewiesen. Als zu übermittelnde Daten wird dem Intent eine Zeichenkette mit Hilfe der putExtra() Methode hinzugefügt. Die Zeichenkette wird unter dem Schlüssel Intent.EXTRA_TEXT abgelegt.

Eine URI wird nicht als Data-Information angegeben, stattdessen wird der MIME type mit Hilfe der setType() Methode auf den Werte „text/plain“ gesetzt. Diese Angabe ist ausreichend, um den zu übertragenden Inhalt exakt zu spezifizieren.

In den Zeilen 7 bis 9 wird überprüft, ob das Android System eine passende Activity auf dem Android Gerät finden kann und anschließend der startActivity() Methode das Intent-Objekt übergeben.

Wenn nun die Methode startActivity() aufgerufen wird, untersucht das Android System alle installierten Apps, um zu bestimmen welche App-Komponenten diese Art Intent ausführen können. Gesucht wird nach einer App-Komponente, die einen Intent mit der Aktion ACTION_SEND ausführen kann, bei dem Daten vom MIME typetext/plain” übertragen werden.

Falls es nur eine App gibt, die diesen Intent verarbeiten kann, wir diese App sofort gestartet und ihr der Intent übergeben. Sollte es mehrere Apps geben, die diese Intent verarbeiten können, öffnet das Android System einen Auswahldialog und der Benutzer muss entscheiden welche App für das Ausführen der per impliziten Intent angeforderten Aufgabe verwendet werden soll.

Es ist auch möglich, dass keine passende App für den auszuführenden impliziten Intent auf dem Android Gerät installiert ist. Falls dies so ist, so darf auf keinen Fall die Methode startActivity() aufgerufen werden. Da sonst die eigene App abstürzen würde. Daher muss vor dem Ausführen eines impliziten Intents immer mit der Methode resolveActivity() sichergestellt werden, dass eine Activity auf dem Gerät installiert ist, welche den impliziten Intent empfangen und verarbeiten kann.

Ist der Rückgabewert der Methode resolveActivity() ungleich null, dann ist auf dem Gerät mindestens eine App installiert, die den Intent bearbeiten kann. Ist der Rückgabewert null, darf der Intent nicht gestartet werden und die Funktion sollte deaktiviert werden, die den impliziten Intent ausgelöst hat.

1.5 Bekannte implizite Intents in Android

Um eine App-fremde Activity in Android starten zu können, muss ein impliziter Intent verwendet werden, der genau zu dem Intent Filter der fremden Activity passt. Das bedeutet, man benötigt genaue Informationen über den Intent Filter der passenden Activity. Doch woher weiß man als App-Entwickler welche Intent Filter die fremden Activities verwenden?

Um diese Problematik zu lösen, sind auf der Developer Webseite von Android häufig genutzte Intents aufgeführt. Auf der Leitfaden-Seite Common Intents werden die verschiedenen impliziten Intents ausführlich vorgestellt. Die Intents sind dabei nach dem App-Typ angeordnet, der den versendeten impliziten Intent verarbeiten wird.

Die folgenden App-Typen verarbeiten häufig genutzte impliziten Intents in Android weiter:

  • Alarm Uhr
  • Kalender
  • Kamera
  • Kontakte
  • E-Mail
  • File-Storage
  • Lokale Aktionen
  • Karten
  • Audio und Video
  • Telefon
  • Suche
  • Einstellungen
  • Text-Nachrichten
  • Web-Browsing

Der für unser Vorhaben relevante App-Typ ist auch in der oberen Liste mit aufgeführt. Und zwar möchten wir die Funktionalität einer Web-Browsing App nutzen, um die Zitat-Autoren auf der Webseite der freien Enzyklopädie Wikipedia nachzuschlagen. Die Web-Browsing App werden wir mit Hilfe eines impliziten Intents aufrufen.

Aus den Ausführungen des oben verlinkten Developer-Guides ist zu entnehmen, dass dem Intent-Objekt als Aktion eine Intent.ACTION_VIEW-Aktion zugewiesen und in sein Data-Feld die URI zur Wikipedia-Webseite eingefügt werden muss, die von der Web-App geöffnet werden soll.

Mit dem folgenden Quellcode wird ein solcher VIEW-Intent erzeugt und zum Aufrufen der passenden Activity an das Android System übergeben:

// Erzeugen des Data-URI Scheme für die anzuzeigende Webseite
String searchUrl  = "https://de.wikipedia.org/w/index.php?search=Friedrich Schiller";
Uri webpageUri = Uri.parse(searchUrl);

// Erzeugen eines impliziten View-Intents mit der Data URI-Information
Intent intent = new Intent(Intent.ACTION_VIEW, webpageUri);

// Prüfen ob eine Web-App auf dem Android Gerät installiert ist 
// und Starten der App mit dem oben erzeugten impliziten View-Intent
if (intent.resolveActivity(getPackageManager()) != null) {
    startActivity(intent);
}

Mit der Anweisung in Zeile 11 wird der erzeugte VIEW-Intent an die Methode startActivity() übergeben. Das Android System sucht dann nach einer installierten Web-App und übergibt dieser den impliziten Intent. Dabei wird die zur Aufgabe passende Activity gestartet und von dieser die übermittelte Webseite angezeigt werden.

Den oben aufgeführten Code werden wir später mit leichten Veränderungen im praktischen Teil dieser Lektion wiederverwenden, um den Autor eines Zitats auf der Wikipedia-Webseite mit Hilfe eines impliziten Intents nachschlagen zu lassen. Der Aufruf wird vom Menü der App Bar der DetailActivity aus erfolgen, welches wir im nächsten Abschnitt noch implementieren müssen.

Wir werden nun ein Menü für die App Bar der DetailActivity implementieren, über das eine App-fremde Web-Browsing Activity mit Hilfe eines impliziten Intents gestartet werden kann. Die fremden Activity wird dann für unsere App die Zitat-Autoren auf der freien Enzyklopädie Wikipedia nachschlagen.

Um das Menü zu implementieren, werden wir neue String-Ressourcen und eine weitere XML-Menüdatei unserem Android Projekt hinzufügen. Die neue XML-Menüdatei wird die beiden Aktionen Autor nachschlagen und Einstellungen besitzen. Mit ihrer Hilfe werden wir dann das Options Menu der DetailActivity aktivieren und die darin definierten Menüeinträge als Aktionen im Overflow Menu der App Bar anzeigen lassen.

Danach werden wir die Auswertungslogik der Aktionen implementieren, so dass später über die Aktion Autor nachschlagen der implizite Intent erzeugt und durch ihn das Starten der App-fremden Activity veranlasst werden kann.

Wir werden nun mit den folgenden drei Schritten das Menü für die App Bar der DetailActivity implementieren:

  1. Namen für die App Bar-Aktionen als String-Ressourcen in der strings.xml Datei definieren.
  2. Definieren der App Bar-Aktionen In der XML-Menüdatei menu_activity_detail.xml.
  3. Laden der App Bar-Aktionen mit Hilfe der onCreateOptionsMenu() Methode und Implementieren der Auswertungslogik in der onOptionsItemSelected() Methode der DetailActivity-Klasse.

2.1 Namen für die App Bar-Aktionen als String-Ressource definieren

Wir definieren nun zwei String-Ressourcen, die wir später als Namen der App Bar-Aktionen wiederverwenden werden. Dazu öffnen wir die strings.xml Ressourcen-Datei im Editor von Android Studio, indem wir doppelt auf ihren Dateinamen im Project Tool Window klicken. Die Datei befindet sich im res/values/ Ordner unseres Projekts.

Dem bereits vorhandenen Code der strings.xml Datei fügen wir die beiden markierten Zeilen hinzu:

strings.xml

<resources>
    <string name="app_name">Zitate</string>

    <string name="welcome_message">Hello CodeYourApp World! als String-Ressource</string>
    <string name="text_button_activity_main">Hole Daten</string>

    <string name="sample_author">Johann Wolfgang v. Goethe</string>
    <string name="sample_quote">Das sicherste Mittel, ein freundschaftliches Verhältnis
        zu hegen und zu erhalten, finde ich darin, daß man sich wechselweise mitteile,
        was man tut. Denn die Menschen treffen viel mehr zusammen in dem, was sie tun,
        als in dem, was sie denken.</string>

    <string name="action_get_data">Hole Daten</string>
    <string name="action_settings">Einstellungen</string>
    <string name="action_lookup_author">Autor nachschlagen</string>
    <string name="action_share_quote">Zitat teilen</string>

</resources>

In der String-Ressource in Zeile 15 speichern wir „Autor nachschlagen“ unter der Ressourcen-ID action_lookup_author als Bezeichner für die App Bar-Aktion ab, die wir später für das Nachschlagen der Zitat-Autoren per impliziten Intent verwenden werden. Auf diese String-Ressource können wir mit R.string.action_lookup_author vom Quellcode aus oder mit @string/action_lookup_author von einer anderen XML-Datei aus zugreifen.

In Zeile 16 legen wir eine weitere String-Ressource mit der Ressourcen-ID action_share_quote an, die den Eintrag „Zitat teilen“ erhält. Sie wird uns als Bezeichner für die Teilen-Aktion dienen, die wir in der nächsten Lektion mit Hilfe des Share Action Providers implementieren werden.

In Android Studio sollte die strings.xml Datei nun wie folgt aussehen:

detailactivity_appbar_aktionen_strings

Die zwei hinzugefügten String-Ressourcen werden wir als App Bar-Aktionen wiederverwenden

In der oberen Abbildung sind die neu eingefügten Zeilen mit einem blauen Rahmen umschlossen (Markierung A). Die String-Ressource action_lookup_author werden wir im nächsten Abschnitt als Bezeichner für die App Bar-Aktion Autor nachschlagen wiederverwenden. Die andere String-Ressource werden wir erst in der nächsten Lektion benötigen.

2.2 Definieren der App Bar-Aktionen in einer XML-Menüdatei

Wir werden nun eine XML-Menü Ressourcen-Datei erstellen und in ihr die Aktionen für die App Bar der DetailActivity definieren. Die neu XML-Menüdatei wird in den Dateinamen menu_activity_detail.xml tragen und wie alle Menüdateien in dem menu-Ordner des Android Projekts abgelegt werden. In der erstellten Menüdatei definieren wir anschließend die Aktionen unserer App Bar per Android XML-Vokabular.

Hinweis: Nur Menüdateien die sich im res/menu/ Ordner befinden, werden beim Kompilieren der App in eine Menu-Ressource umgewandelt. Zudem wird beim Kompilieren auch die lokale Ressourcen-Klasse R generiert, welche die IDs für alle Ressourcen innerhalb des gesamten res/ Verzeichnisses enthält.

Mit den folgenden Schritten erstellen wir nun die XML-Menüdatei menu_activty_detail.xml in den res/menu/ Ressourcen-Ordner unseres Android Projekts:

  1. Mit der rechten Maustaste auf den Ordner menu/ in dem Project Tool Window klicken.
  2. Anschließend den Eintrag New des Kontext-Menüs anklicken.
  3. Danach auf Menu resource file klicken.
detailactivity_create_menufile

Erstellen eines Menu Resource file für die Aktionen der App Bar der DetailActivity

Anschließend öffnet sich der New Menu Resource File-Dialog, in welchem wir den Namen der zu erstellenden XML-Menüdatei vorgeben müssen:

detailactivity_new_menu_file_dialog

Dateinamen für die neue XML-Menüdatei vorgeben

Wir tragen in das Feld Enter a new file name den Dateinamen menu_activity_detail.xml ein und bestätigen anschließend den Dialog mit einem Klick auf den OK Button.

Die neue XML-Ressourcen Datei wird nun automatisch von Android Studio erstellt und im Editorfenster der IDE geöffnet wird. Falls die Datei nicht automatisch geöffnet wurde, führen wir das Öffnen manuell durch. Dazu klicken wir doppelt auf ihren Dateinamen menu_activity_detail.xml im Project Tool Window von Android Studio. Die Datei befindet sich im res/menu/ Ordner unseres Projekts.

Standardmäßig öffnet sich das Editorfenster in der Design-Ansicht. Damit der XML-Code der Menü Datei angezeigt wird, müssen wir unten im Editorfenster den Tab Text anklicken.

Den generierten XML-Code löschen wir vollständig und fügen an dessen Stelle den folgenden XML-Code ein:

menu_activity_detail.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <!-- "Lookup Author", soll immer im Overflow-Menü angezeigt werden -->
    <item
        android:id="@+id/action_lookup_author"
        android:orderInCategory="1"
        android:title="@string/action_lookup_author"
        app:showAsAction="never" />

    <!-- "Settings", soll immer im Overflow-Menü angezeigt werden -->
    <item
        android:id="@+id/action_settings"
        android:orderInCategory="9"
        android:title="@string/action_settings"
        app:showAsAction="never" />

</menu>

Mit dem oberen Quellcode haben wir eine Android Menu Resource definiert. Wir werden sie später von einem MenuInflater zu einem Menu-Objekt umwandeln lassen, welches wir für das Erzeugen des Options Menus unserer DetailActivity verwenden werden. Da in Android das Options Menu automatisch auch als das App Bar-Menü verwendet wird, werden auf diese Weise die Aktionen der App Bar nach den Vorgaben dieser Menu Resource definiert.

Eine Menu Resource besitzt immer genau ein <menu> Wurzelelement, welches im Inneren <item> und <group> Elemente enthält. In unserem Fall besitzt das <menu> Element zwei <item> Tochterelemente, welche die beiden Einträge des Menüs repräsentieren. Jedem <item> Element wurde eine eigene ID zugewiesen, über die wir später prüfen können, ob der entsprechende Menüeintrag vom Nutzer angeklickt wurde.

Für die beiden <Item> Elemente, haben wir jeweils eine neue ID mit folgender Schreibweise: android:id=“@+id/element_name“ anlegen lassen. Durch das @ Symbol weiß der XML-Parser, dass es sich um eine ID-Ressource handelt. Das + Symbol gibt an, dass die ID-Ressource in der R.java Datei neu angelegt werden muss.

Zusätzlich haben wir für beide Elementen weitere Eigenschaften mit folgenden Attributen definiert:

  • android:orderInCategory – Gibt die Reihenfolge der Menüeinträge an, je niedriger die Zahl desto weiter oben wird der jeweilige Eintrag im Menü angeordnet. Da in Android auch Menüs miteinander verschmolzen werden können, lassen sich auf diese Weise die Menüeinträge effektiv ordnen.

  • android:title – Legt den Titel des Menüeintrags fest. Der Eintrag wird unter diesem Titel im Overflow Menu der App Bar angezeigt. Wenn der Menüeintrag als Action-Button in der App Bar erscheint, wird nur der entsprechende Icon dargestellt, nicht aber der Titel.

  • app:showAsAction – Mit diesem Attribut wird vorgegeben, ob der Menüeintrag als Action-Button in der App Bar oder als Text im Overflow Menu der App Bar erscheinen soll. Als Vorgaben stehen ifRoom, withText, never und always zur Auswahl bereit.

In Android Studio sollte die menu_activity_detail.xml Datei nun wie folgt aussehen:

detailactivity_appbar_menu_code

Die XML-Menüdatei menu_activity_detail.xml mit dem eingefügten Quellcode

Wir haben nun die XML-Menüdatei für die App Bar-Aktionen der DetailActivity definiert. Als Nächstes müssen die beiden Aktionen der App Bar mit Hilfe der onCreateOptionsMenu() Methode zugewiesen werden.

2.3 Laden der App Bar-Aktionen und Implementieren der Auswertungslogik

Damit die eben definierten Aktionen auch von der App Bar der DetailActivity angezeigt werden, müssen wir die neu erstellte XML-Menüdatei menu_activity_detail.xml für das Options Menu und somit auch für die App Bar aktivieren. Dies wird in der onCreateOptionsMenu() Methode der DetailActivity-Klasse erfolgen, welche vom Android System automatisch aufgerufen wird, sobald das Options Menu das erste Mal angezeigt wird.

Die Auswertungslogik des aktivierten Menüs werden wir anschließend in der onOptionsItemSelected() Methode der DetailActivity-Klasse implementieren. Mit der Logik werden wir prüfen, welche Aktion in der App Bar angeklickt wurde und entsprechend darauf reagieren.

Wir öffnen nun die Klassendatei DetailActivity.java im Editor von Android Studio mit einem Doppelklick auf ihren Dateinamen im Project Tool Window. Die Klassendatei befindet sich im Package-Ordner de.codeyourapp.zitate unseres Projekts.

Alle in die DetailActivity.java Datei eingefügten Codezeilen sind markiert worden:

An dieser Stelle endet der freie Inhalt dieser Lektion. Wir hoffen, sie hat dir bis hierher gefallen! Du kannst sie im geschützten Bereich von ProgrammierenLernenHQ fortsetzen, in welchem sich alle Lektionen unserer Android Online-Kurse befinden.

Unsere Android Kurse bestehen aus insgesamt 43 großen Lektionen und sind unterteilt in 13 frei zugängliche und 30 Premium-Lektionen. Die Premium-Lektionen befinden sich in dem geschützten Bereich und sind nur für Käufer unseres Android Online-Kurs Gesamtpaket zugänglich.

plhq_teaser_hbox_gelb_fotolia_RA Studio_46292813 An dieser Stelle endet der freie Inhalt dieser Lektion. Wir hoffen, sie hat dir bis hierher gefallen! Du kannst sie durch Kauf unseres Android Online-Kurs Gesamtpakets freischalten.

In unserem Android Online-Kurs Gesamtpaket befinden sich 43 große Lektionen, in denen wir dir schrittweise zeigen, wie voll funktionstüchtige Android Apps programmiert werden.

Diese Lektion ist Teil unseres Android Gesamtpakets. Insgesamt sind unsere Online-Kurse unterteilt in 13 frei zugängliche und 30 Premium-Lektionen.

Die Premium-Lektionen befinden sich in dem geschützten Bereich und sind nur für Käufer des Android Online-Kurs Gesamtpakets zugänglich.



Welche Inhalte befinden sich im Android Online-Kurs Gesamtpaket?

  • Das Gesamtpaket enthält alle Android Online-Kurse von ProgrammierenLernenHQ.
  • Im Paket enthalten ist unser großer Android Apps Programmieren Online-Kurs. Er ist unser Hauptkurs und besteht aus 35 großen Lektionen. Die Grundlagen der Android App Entwicklung praxisnah und verständlich zu lehren, ist das Hauptziel des Android Apps Programmieren Kurses.
  • Im Paket enthalten ist auch unser SQLite Datenbank App Programmieren Online-Kurs. Dieser Spezialkurs besteht aus 8 großen Lektionen und ist als weiterführender Kurs konzipiert worden. Der Kurs schließt an unseren Android Apps Programmieren Hauptkurs an und widmet sich dem speziellen Thema der SQLite Datenbanken.
  • Durch den Kauf erhältst du unbegrenzten Zugang zu allen Inhalten unseres Android Online-Kurs Gesamtpakets. Wir werden in Zukunft weitere Lektionen hinzufügen. Auch auf alle zukünftigen Lektionen erhältst du vollen Zugriff.

Wir hoffen, Dich bald als neuen Kursteilnehmer unserer Android Online-Kurse begrüßen zu dürfen!

Einmal kaufen und dadurch zeitlich unbegrenzten Zugriff auf alle Inhalte unseres Android Online-Kurs Gesamtpakets erhalten.



Hinweis: Der untere Quellcode ist Teil des geschützten Bereichs von ProgrammierenLernenHQ. Durch Freischalten unserer Android Online-Kurse erhältst du Zugriff auf alle geschützten Inhalte.
Erfahre mehr über unsere Android Online-Kurse.

android_programmieren_lernen_blurry_sourcecode

Der obere Quellcode ist Teil des geschützten Bereichs. Durch Freischalten unserer Android Online-Kurse erhältst du Zugriff auf alle geschützten Inhalte. Klicke auf die Info-Box, um mehr zu erfahren.

Im oberen Quellcode der DetailActivity-Klasse wurden an mehreren Stellen Änderungen vorgenommen. Die eingefügten Zeilen sind markiert worden. Wir werden nun die durchgeführten Änderungen der Reihe nach besprechen.

In den Zeile 3 bis 5 werden die Klassen Menu, MenuItem und Toast mittels Import-Anweisungen innerhalb der DetailActivity-Klasse sichtbar gemacht, so dass wir sie ohne den Namen ihres Packages verwenden können.

In den Zeilen 56 bis 59 wird die onCreateOptionsMenu() Methode definiert. In der Methode wird zuerst ein MenuInflater-Objekt angefragt. Auf diesem Objekt wird die inflate() Methode aufgerufen und ihr die Ressourcen-ID der im vorherigen Abschnitt definierten Menu Resource übergeben. Auf diese Weise wird das Options Menu basierend auf der übergebenen Menu Resource erzeugt und dabei gleichzeitig für die App Bar aktiviert.

Die onOptionsItemSelected() und lookupAuthor() Methoden

In den Zeilen 62 bis 79 wird die onOptionsItemSelected() Methode und in den Zeilen 81 bis 85 die lookupAuthor() Methode definiert. Zu Übersichtlichkeit sind beide Methoden an dieser Stelle nochmals aufgeführt:

public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.action_lookup_author:
            lookupAuthor();
            return true;

        case R.id.action_settings:
            Toast toast = Toast.makeText(getApplicationContext(),
                    "Der Einstellungen-Menüeintrag wurde angeklickt.", Toast.LENGTH_LONG);
            toast.show();
            return true;

        default:
            // Wenn wir hier ankommen, wurde eine unbekannt Aktion erfasst.
            // Daher erfolgt der Aufruf der Super-Klasse, die sich darum kümmert.
            return super.onOptionsItemSelected(item);
    }
}

private void lookupAuthor() {
    String message = "Der Autor nachschlagen-Menüeintrag wurde angeklickt.";
    Toast toast = Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG);
    toast.show();
}

In der onOptionsItemSelected() Methode haben wir die Auswertungslogik implementiert, mit der wir Klicks auf Aktionen der App Bar erfassen und entsprechend darauf reagieren. Die Methode wird immer dann vom Android Framework aufgerufen, wenn der Benutzer auf ein Menüelement des Option Menus klickt. Dies ist auch der Fall, wenn eine Aktion der App Bar angeklickt wird.

Bei Aufruf der onOptionsItemSelected() Methode wird ihr das angeklickte Menü-Objekt übergeben, welches zum erfolgten Aufruf führte. Die ID des Menüelements kann mit der getItemId() angefordert werden. Über die ID kann leicht geprüft werden, welcher Menüeintrag bzw. welche Aktion der App Bar vom Nutzer angeklickt wurde. Am besten verwendet man dafür ein Switch-Case Statement und führt eine Fallunterscheidung wie im oberen Quellcode gezeigt durch.

In Zeile 3 der onOptionsItemSelected() Methode prüfen wir, ob die Aktion mit der ID R.id.action_lookup_author angeklickt wurde. War dies der Fall, dann wird die Methode lookupAuthor() aufgerufen und der Wert true zurückgegeben. Durch den Rückgabewert true wird dem Android System mitgeteilt, dass die angeforderte Aktion behandelt wurde.

In Zeile 7 wird geprüft, ob die Aktion mit der ID R.id.action_settings angeklickt wurde. Wenn dem so ist, wird ein Toast-Objekt erzeugt und auf dem Display ausgegeben. Später werden wir an dieser Stelle das Einstellungen-Menü von der Aktion öffnen lassen.

In den Zeilen 20 bis 24 wird die lookupAuthor() Methode definiert. Momentan wird durch sie eine kurze Toast-Meldung ausgegeben. Später werden wir von ihr den impliziten Intent erzeugen lassen, durch den das Nachschlagen der Zitat-Autoren an eine App-fremde Activity delegiert wird.

Weitere Änderungen sind nicht an der DetailActivity.java Datei vorzunehmen. In Android Studio sollte die DetailActivity-Klasse nun wie folgt aussehen:

android_programmieren_lernen_blurry_sourcecode

Der obere Quellcode ist Teil des geschützten Bereichs. Durch Freischalten unserer Android Online-Kurse erhältst du Zugriff auf alle geschützten Inhalte. Klicke auf die Info-Box, um mehr zu erfahren.

In der oberen Abbildung ist die überarbeitete DetailActivity.java Klassendatei dargestellt. Der Quellcode wurde an vier Stellen erweitert. Es sind nur die hinzugefügten Methoden aufgeklappt worden. Die onCreate() Methode ist nicht verändert worden und daher zugeklappt geblieben.

Welche Bedeutung der jeweilige Code-Block besitzt, ist in der unteren Liste angegeben:

  1. B – Die benötigten Import-Anweisungen zum Sichtbarmachen der Klassen Menu, MenuItem und Toast.
  2. C – Die onCreateOptionsMenu() Methode mit der das Options Menu erstellt wird.
  3. D – Die onOptionsItemSelected() Methode, in der die Auswertungslogik der App Bar implementiert wird.
  4. E – Die lookupAuthor() Methode, von der später der implizite Intent erzeugt wird.

Wir haben nun die App Bar für unsere DetailActivity aktiviert, ihr Aktionen mit Hilfe des Options Menu zugewiesen und ihre Auswertungslogik implementiert. Die hinzugefügten App Bar-Aktionen werden nun in unserer Android App angezeigt. Zudem werden Klicks auf die Aktionen von der App Bar erfasst und entsprechend darauf reagiert.

Im nächsten Abschnitt werden wir unsere App im Emulator auf einem Android Virtual Device ausführen und prüfen, wie die Anwendung reagiert, wenn die Aktionen der App Bar angeklickt werden.

2.4 Testen des App Bar-Menüs auf einem AVD im Emulator

Wir werden nun unserer Android App auf einem Android Virtual Device im Emulator ausführen lassen. Auf diese Weise können wir direkt überprüfen, wie unsere App reagiert, wenn die aktivierten App Bar-Aktionen angeklickt werden.

Unsere App starten wir dazu wie gewohnt über den Run > Run 'app' Menüeintrag, den wir über die obere Menüleiste erreichen.

In den unteren Abbildungen ist unsere Android App auf dem virtuellen Gerät zu sehen. Wir haben zunächst durch Anklicken eines ListView-Eintrags der MainActivity die DetailActivity öffnen lassen. Wie zu erkennen ist, besitzt die App Bar unserer DetailActivity nun ein Overflow Menu mit zwei Menüeinträgen:

screenshot_intent_1a

Die DetailActivity besitzt nun ein Overflow Menu

screenshot_intent_2a

Das Overflow Menu besteht aus zwei Aktionen


screenshot_intent_3a

Durch Anklicken der Autor nachschlagen Aktion wird eine kurze Toast-Meldung zu Testzwecken ausgegeben

In der großen Abbildung ist der Aufbau der App Bar dargestellt. Sie besteht aus einem Titel, einem Up-Button und einem Overflow Menu-Button. Durch Klick auf den Overflow Menu-Button, klappt das Overflow Menu mit seinem Menüeinträgen Autor nachschlagen und Einstellungen auf. Klickt man nun auf einen der beiden Einträge, wird eine kurze Meldung auf dem Android Gerät ausgegeben, die den Benutzer informiert, dass der jeweilige Menüeintrag angeklickt wurde.

Da nun sichergestellt ist, dass die beiden Aktionen der App Bar korrekt aktiviert wurden, können wir als Nächstes mit dem Implementieren des impliziten Intents beginnen. Das Intent-Objekt wird von der lookupAuthor() Methode erzeugt werden und für das Starten der App-fremden Activity verantwortlich sein.

3. Starten einer App-fremden Activity mit Hilfe eines impliziten Intents in Android

Unsere DetailActivity verfügt nun über eine App Bar mit einem funktionierenden Overflow Menu, das die beiden Aktionen Autor nachschlagen und Einstellungen enthält. Über den Autor nachschlagen Menüeintrag möchten wir nun eine App-fremde Activity starten und von dieser den angezeigten Zitat-Autor auf der freien Enzyklopädie Wikipedia nachgeschlagen lassen.

Um dieses Vorhaben umzusetzen, müssen wir die lookupAuthor() Methode der DetailActivity-Klasse überarbeiten. Und zwar so, dass von ihr ein impliziter Intent erzeugt und an das Android System zum Starten der fremden Activity übergeben wird. Dabei müssen dem Intent-Objekt Informationen über die auszuführende Aktion und die dafür benötigten Daten übergeben werden.

Anschließend muss das Intent-Objekt per startActivity() an das Android System übergeben werden, welches anhand der Intent-Informationen die passende Web-Browsing App findet und deren zuständige Activity startet.

Wir öffnen erneut die Klassendatei DetailActivity.java im Editor von Android Studio mit einem Doppelklick auf ihren Dateinamen im Project Tool Window. Diesmal muss nur der Quellcode ihrer lookupAuthor() Methode überarbeitet und eine Import-Anweisung hinzugefügt werden.

Alle in die DetailActivity.java Datei überarbeiteten bzw. hinzugefügten Codezeilen sind markiert worden:

android_programmieren_lernen_blurry_sourcecode

Der obere Quellcode ist Teil des geschützten Bereichs. Durch Freischalten unserer Android Online-Kurse erhältst du Zugriff auf alle geschützten Inhalte. Klicke auf die Info-Box, um mehr zu erfahren.

In dem oben aufgeführten Quellcode der DetailActivity.java Datei wurde die Methode lookupAuthor() bereits überarbeitet. Zudem wurde die Klasse Uri per Import-Anweisung sichtbar gemacht. Weitere Änderungen sind nicht an der DetailActivity-Klasse vorgenommen worden.

In Zeile 3 wird die Uri-Klassen mittels Import-Anweisungen innerhalb der DetailActivity-Klasse sichtbar gemacht, so dass wir sie ohne den Namen ihres Packages verwenden können.

Die überarbeitete Methode lookupAuthor() in den Zeilen 82 bis 104 wurde ebenfalls markiert. In ihr wurde der Quellcode für das Erzeugen des impliziten Intent und Starten der App-fremden Activity eingefügt. Dabei wurde der bisherige Quellcode der Methode überschrieben. Um Programmierfehler zu vermeiden, ist es sicherer, die Methode daher vollständig durch den oben markierten Quellcode zu ersetzten.

Die lookupAuthor() Methode

Wie bereits weiter oben erwähnt, wird in den Zeilen 82 bis 104 der DetailActivity-Klasse die lookupAuthor() Methode definiert. Sie wird aufgerufen, sobald der Benutzer auf den Autor nachschlagen Menüeintrag klickt und ist für das Nachschlagen der Zitat-Autoren per impliziten Intent verantwortlich.

Wie sie dies ausführt, werden wir nun genauer betrachten. Die Methode ist daher zur Übersichtlichkeit an dieser Stelle nochmals aufgeführt:

private void lookupAuthor() {
    Intent receivedIntent = getIntent();
    if (receivedIntent != null && receivedIntent.hasExtra(EXTRA_QUOTE_AUTHOR)) {

        // Erzeugen der Suchanfrage-URL aus den Daten des empfangenen Intents
        String quoteAuthor = receivedIntent.getStringExtra(EXTRA_QUOTE_AUTHOR);
        String searchQueryUrl  = "https://de.wikipedia.org/w/index.php?search=" + quoteAuthor;

        // Erzeugen eines impliziten View-Intents mit der Data URI-Information
        Uri webpageUri = Uri.parse(searchQueryUrl);
        Intent intent = new Intent(Intent.ACTION_VIEW, webpageUri);

        // Prüfen ob eine Web-App auf dem Android Gerät installiert ist
        // und Starten der App mit dem oben erzeugten impliziten View-Intent
        if (intent.resolveActivity(getPackageManager()) != null) {
            startActivity(intent);
        } else {
            Toast toast = Toast.makeText(getApplicationContext(),
                    "Keine Web-App installiert!", Toast.LENGTH_LONG);
            toast.show();
        }
    }
}

Zuerst wird in Zeile 2 das empfangene Intent-Objekt angefragt. Dabei handelt es sich um den Intent durch den die DetailActivity-Klasse gestartet wurde. Also um den expliziten Intent, welchen wir in der vorherigen Lektion implementiert haben. Dieser enthält in seinem Extras-Feld Informationen über den Autor, das Autorenbild und den Zitattext.

Der anschließende if-Block wird nur betreten, falls ein empfangenes Intent-Objekt existiert und es Informationen über den Zitat-Autor in sich trägt. Ob solche Informationen im Intent vorhanden sind, wird mit der Methode hasExtra() und dem Schlüssel EXTRA_QUOTE_AUTHOR, dem der Autorenname hinterlegt ist, überprüft.

In den Zeilen 6 und 7 wird die Suchanfrage-URL erstellt. Dazu wird mit der Methode getStringExtra() der unter dem Schlüssel EXTRA_QUOTE_AUTHOR hinterlegte Autorenname ausgelesen und der Wikipedia-Adresse als Suchparameter hinzugefügt.

Anschließend wird in den Zeile 10 und 11 die URI mit Hilfe der zusammengebauten Suchanfrage-URL erstellt. Die URI wird danach dem Intent-Konstruktor zusammen mit der auszuführenden Aktion, Intent.ACTION_VIEW, übergeben und dadurch der implizite Intent erzeugt. Dabei wird vom Konstruktor die übergebene Aktion in das Action-Feld und die übergebene URI in das Data-Feld des erzeugten Intent-Objekts geschrieben.

Mit diesen beiden Informationen ist der implizite Intent ausreichend genau beschrieben, so dass das Android System die zu ihm passende Activity durch Vergleichen der Intent Filter aller auf dem Android Gerät installierten Apps bestimmen kann.

In Zeile 16 wird das erzeugte Intent-Objekt mit Hilfe der startActivity Methode an das Android System übergeben und dadurch das Starten der App-fremden Activity vom System angefordert. Dies geschieht aber nur, falls das Android System auch eine zum impliziten Intent passende App auf dem Android Gerät finden konnte. Ist keine passende App auf dem Gerät installiert, wird der innere if-Block nicht betreten und stattdessen eine Meldung an den Benutzer ausgegeben.

Hinweis: Diese Vorprüfung, ob der implizite Intent auf dem Android Gerät auflösbar ist, muss zwingend durchgeführt werden. Ist keine passende App auf dem Android Gerät installiert, darf auf keinen Fall die Methode startActivity() aufgerufen werden. Da sonst die eigene App abstürzen würde. Daher muss vor dem Ausführen eines impliziten Intents immer mit der Methode resolveActivity() sichergestellt werden, dass eine Activity auf dem Gerät installiert ist, welche den impliziten Intent empfangen und verarbeiten kann.

In Android Studio sollte der Inhalt der DetailActivity.java Klassendatei nun wie folgt aussehen:

android_programmieren_lernen_blurry_sourcecode

Der obere Quellcode ist Teil des geschützten Bereichs. Durch Freischalten unserer Android Online-Kurse erhältst du Zugriff auf alle geschützten Inhalte. Klicke auf die Info-Box, um mehr zu erfahren.

In der oberen Abbildung ist die überarbeitete DetailActivity.java Klassendatei dargestellt. Der Quellcode wurde diesmal an zwei Stellen verändert. Es sind nur die in dieser Lektion hinzugefügten Methoden aufgeklappt worden. Die onCreate() Methode ist nicht verändert worden und daher zugeklappt geblieben.

Welche Bedeutung der jeweilige Code-Block besitzt, ist in der unteren Liste angegeben:

  1. F – Die benötigte Import-Anweisung zum Sichtbarmachen der Klasse Uri.
  2. G – Die lookupAuthor() Methode, in der nun der implizite Intent erzeugt und die App-fremde Activity gestartet wird.

Wir haben nun alle erforderlichen Änderungen an der DetailActivity-Klasse vorgenommen. Von der überarbeiteten lookupAuthor() Methode lassen wir nun einen impliziten Intent erzeugen und durch ihn eine App-fremde Activity starten. Dies wird immer dann erfolgen, sobald der Benutzer auf den Autor nachschlagen Menüeintrag des Overflow Menu klickt.

4. Ausführen und Testen unserer Android App

Wir werden nun unserer Android App auf einem Android Virtual Device im Emulator ausführen lassen und überprüfen, wie unsere Anwendung die App-fremde Activity per impliziten Intent startet.

Unsere App starten wir dazu wie gewohnt über den Run > Run 'app' Menüeintrag, den wir über die obere Menüleiste erreichen.

Sobald unsere App auf dem AVD gestartet wurde, führen wir die folgenden Schritte aus:

  1. Wir navigieren durch Anklicken eines ListView-Eintrags von der MainActivity zur DetailActivity.
  2. Danach klicken wir auf den Autor nachschlagen Menüeintrag im Overflow Menu der DetailActivity.
  3. Nun startet das Android System die App-fremde Activity, die den übermittelten Autor auf Wikipedia nachschlägt.
screenshot_intent_4a

1: Klick auf einen beliebigen ListView-Eintrag

screenshot_intent_5a

2: Autor nachschlagen im Overflow Menu anklicken


screenshot_intent_6a

3: Der Autor wird auf Wikipedia von einer App-fremden Activity nachgeschlagen

Auf dem Android Virtual Device ist als Web-Browsing App Google Chrome installiert. Das Android System wird daher diese App starten und ihr den impliziten Intent übergeben. Das Intent-Objekt enthält die URI zur Wikipedia-Webseite, wodurch die ausgewählte Web-Browsing App in der Lage ist, den Zitat-Autor für uns dort nachzuschlagen.

Zusammenfassung

In dieser Lektion haben wir eine App-fremde Activity mit Hilfe eines impliziten Intents vom Android System starten lassen. Die fremde Activity haben wir zum Nachschlagen der Zitat-Autoren auf der freien Enzyklopädie Wikipedia genutzt.

Zum Starten der fremden Activity haben wir diesmal aber nicht ihren Namen explizit angeben, sondern die von ihr auszuführende Aufgabe mit Hilfe der Action-, Data– und Category-Felder im Intent-Objekt exakt beschreiben. Das Android System konnte anhand dieser im Intent-Objekt gespeicherten Informationen die zur angeforderten Aufgaben passende Activity finden und für uns ausführen.

Wie dies mit Hilfe des impliziten Intents in Android realisiert wird, haben wir ausführlich im theoretische Teil dieser Lektion kennengelernt und dabei erfahren aus welchen Komponenten ein impliziter Intent besteht, was Intent Filter sind und wie das Android System die zum Intent passende Activity auswählt.

Anschließend haben wir im praktischen Teil dieser Lektion ein Menü für die App Bar der DetailActivity implementiert, über das die App-fremde Activity gestartet wird. Dazu haben wir neue String-Ressourcen und eine weitere XML-Menüdatei, mit den beiden Aktionen Autor nachschlagen und Einstellungen, unserem Android Projekt hinzugefügt.

Mit Hilfe der neu erstellten Menüdatei haben wir dann das Options Menu der DetailActivity aktiviert und die darin definierten Menüeinträge als Aktionen im Overflow Menu der App Bar anzeigen lassen. Danach haben wir die Auswertungslogik des Option Menu implementiert, so dass über die Aktion Autor nachschlagen der implizite Intent erzeugt und durch ihn das Starten der App-fremden Activity veranlasst wird.

Abschließend haben wir unsere Android App im Emulator auf einem Android Virtual Device ausgeführt und geprüft, ob das Android System die zur angeforderten Aufgabe passende Activity per impliziten Intent startet und ob diese die ihr übertragene Aufgabe zufriedenstellend ausführt.

In der nächsten Lektion werden wir eine weitere sehr nützliche Funktion des Android Intent Systems kennenlernen. Wir werden für unsere App einen ShareActionProvider implementieren, mit dem bequem und intuitiv Inhalte geteilt werden können. Das Teilen wird über einen Action-Button der App Bar in der DetailActivity erfolgen.

Weiterführende Literatur




Comments 7

  1. An die Macher dieses Tutorial,
    meine Hochachtung für die hier geleistete Arbeit. Man kann sich sehr leicht das für die Android-Programmierung notwendige Grundwissen aneignen. Habt Ihr toll gemacht.
    Leider hält YAHOO inzwischen die URL
    http://finance.yahoo.com/1?s=BMW.DE
    nicht mehr bereit, so dass man keine weiteren Info’s abrufen und anzeigen kann.
    Dennoch sieht man natürlich, wie ein impliziter Intent funktioniert und was er macht.
    Danke dafür

    1. Post
      Author

      Hallo Volker,

      vielen Dank für die lobenden Worte und den Hinweis. Ich werde die Such-URL bei der nächsten Aktualisierung des Tutorials anpassen, so dass wieder die zugehörigen Aktienkurse angezeigt werden.

      Viele Grüße, Chris

  2. Wahnsinn, ich liebe dieses Tutorial, es ist wirklich super! Bisher hat alles einwandfrei funktioniert. Ich hätte nie gedacht, dass es so viel Spaß machen würde das alles zu lernen. Großes Lob an dich!

    1. Post
      Author
  3. Hallo
    Zunächst grosses Lob und vielen Dank für dieses Tutorial, wirklich super.
    Nun hat bis Teil 11 auf meinem Galaxy Note 3 alles geklappt, aber jetzt in Teil 12 mit Aufruf eines Browsers stürzt die App ab nachdem ich auf einen Wert geklickt habe (Aktualisierung funktioniert) und produziert die folgenden Fehlermeldungen.

    java.lang.RuntimeException: Unable to start activity ComponentInfo{ich.aktiehq/ich.aktiehq.AktiendetailActivity}: android.view.InflateException: Binary XML file line #3: Error inflating class fragment
    Caused by: android.view.InflateException: Binary XML file line #3: Error inflating class fragment                                                             
    Caused by: android.app.Fragment$InstantiationException: Unable to instantiate fragment ich.aktiehq.AktiendetailFragment: make sure class name exists, is public, and has an empty constructor that is public                                                                
    Caused by: java.lang.ClassNotFoundException: Didn't find class "ich.aktiehq.AktiendetailFragment" on path: DexPathList[[zip file "/data/app/ich.aktiehq-2/base.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]                                                                                                                       
    Suppressed: java.lang.ClassNotFoundException: ich.aktiehq.AktiendetailFragment                                   
    Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack available
    
    1. Post
      Author

      Hallo Dieter,

      danke für das Lob!

      Die Klasse AktiendetailActivity wird nicht gefunden. Es könnte ein Tippfehler in Deinem Quellcode sein. Tippfehler schleichen sich schnell ein. Wenn Du möchtest, kannst Du mir Deine Projektdateien als ZIP per E-Mail zusenden. Ich werde dann mal drüber schauen, vielleicht kann ich den Fehler finden. Die E-Mail Adresse kannst Du im Impressum nachschauen.

      Viele Grüße, Chris

  4. Pingback: Android Tutorial: Der ShareActionProvider in Android

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.