13
52 MOBILE DEVELOPMENT 1/2014 Google stellt Android 4.4 vor Zwischenversion Entwicklerschaft und Auguren wurden von Google gleichermaßen kalt erwischt: Man erwartete die Auslieferung von Android 5.0 – und bekam stattdessen eine als Android 4.4 bezeichnete Zwischenversion. Von Tam Hanna Im Moment ist kein für x86-Prozessoren opti- miertes Emulator-Image erhältlich. Dessen Ver- fügbarkeit dürfte allerdings nur eine Frage der Zeit sein. Die wesentlich höhere Performance auf CPUs mit Hardwarevirtualisierung lässt dessen Einsatz mehr als ratsam erscheinen. Mehr Schutz für SD-Karten Bisher waren die öffentlichen Teile des internen Speichers des Telefons für alle Programme zu- gänglich. Werbefinanzierte Applikationen nut- zen die dort befindlichen Daten für diverse Tra- ckingprozesse, weshalb das API-Level 16 eine als READ_EXTERNAL_STORAGE bezeichnete Permission einführte. Dieses für den Zugriff auf die öffentlichen Teile der SD-Karte notwendige Flag wurde bis- her nur dann ausgewertet, wenn das dafür zu- ständige Flag in den Entwickleroptionen gesetzt war. In Android 4.4 schaltet Google auf scharf: Wenn Ihrem Programm die Permission fehlt, scheitert der Zugriff auf die externe Karte. O bwohl die Änderungen an der Versions- nummer vergleichsweise klein ausfallen, ist Googles neues Betriebssystem mit einer Viel- zahl neuer Funktionen ausgestattet. Einige da- von wirken sich auch auf existierende Program- me aus, weshalb sich Anbieter von Android- Produkten auf jeden Fall mit den Neuerungen befassen sollten. Das aus Entwicklersicht als API Level 19 be- zeichnete Betriebssystem wurde im Zusam- menspiel mit dem Galaxy Nexus 5 vorgestellt. Das von LG hergestellte Smartphone ist ver- gleichsweise preiswert und in ausreichender Stückzahl erhältlich. Trotz der wesentlich redu- zierten Hardware-Anforderungen dürften vie- le Hersteller nicht alle kompatiblen Geräte mit dem neuen Betriebssystem ausstatten. Alternativ bietet sich die Verwendung des Emulators an. Dieser lässt sich durch das Öffnen des Android SDK Managers in Eclipse aufrufen: Aktualisieren Sie die vorinstallierten Werkzeu- ge und laden Sie danach alle unter dem Node Android 4.4 findbaren Pakete herunter (Bild 1). Tam Hanna ist Autor, Trainer und Berater mit den Schwerpunkten Webent- wicklung und Webtechnologien. Er bloggt sporadisch unter: www.tamoggemon.com Inhalt Google stellt Android 4.4 vor. AUTOR

52 - webundmobile.de...52 MOBILE DEVELOPMENT 12014 Google stellt Android 4.4 vor Zwischenversion Entwicklerschaft und Auguren wurden von Google gleichermaßen kalt erwischt: Man erwartete

  • Upload
    others

  • View
    3

  • Download
    0

Embed Size (px)

Citation preview

Page 1: 52 - webundmobile.de...52 MOBILE DEVELOPMENT 12014 Google stellt Android 4.4 vor Zwischenversion Entwicklerschaft und Auguren wurden von Google gleichermaßen kalt erwischt: Man erwartete

52

MOBILE DEVELOPMENT

1/2014

Google stellt Android 4.4 vor

ZwischenversionEntwicklerschaft und Auguren wurden von Google gleichermaßen kalt erwischt: Man erwartete die Auslieferung von Android 5.0 – und bekam stattdessen eine als Android 4.4 bezeichnete Zwischenversion. Von Tam Hanna

Im Moment ist kein für x86-Prozessoren opti-miertes Emulator-Image erhältlich. Dessen Ver-fügbarkeit dürfte allerdings nur eine Frage der Zeit sein. Die wesentlich höhere Performance auf CPUs mit Hardwarevirtualisierung lässt dessen Einsatz mehr als ratsam erscheinen.

Mehr Schutz für SD-Karten

Bisher waren die öffentlichen Teile des internen Speichers des Telefons für alle Programme zu-gänglich. Werbefinanzierte Applikationen nut-zen die dort befindlichen Daten für diverse Tra-ckingprozesse, weshalb das API-Level 16 eine als READ_EXTERNAL_STORAGE bezeichnete Permission einführte.

Dieses für den Zugriff auf die öffentlichen Teile der SD-Karte notwendige Flag wurde bis-her nur dann ausgewertet, wenn das dafür zu-ständige Flag in den Entwickleroptionen gesetzt war. In Android 4.4 schaltet Google auf scharf: Wenn Ihrem Programm die Permission fehlt, scheitert der Zugriff auf die externe Karte.

Obwohl die Änderungen an der Versions-nummer vergleichsweise klein ausfallen, ist

Googles neues Betriebssystem mit einer Viel-zahl neuer Funktionen ausgestattet. Einige da-von wirken sich auch auf existierende Program-me aus, weshalb sich Anbieter von An droid-Produkten auf jeden Fall mit den Neuerungen befassen sollten.

Das aus Entwicklersicht als API Level 19 be-zeichnete Betriebssystem wurde im Zusam-menspiel mit dem Galaxy Nexus 5 vorgestellt. Das von LG hergestellte Smartphone ist ver-gleichsweise preiswert und in ausreichender Stückzahl erhältlich. Trotz der wesentlich redu-zierten Hardware-Anforderungen dürften vie-le Hersteller nicht alle kompatiblen Geräte mit dem neuen Betriebssystem ausstatten.

Alternativ bietet sich die Verwendung des Emulators an. Dieser lässt sich durch das Öffnen des Android SDK Managers in Eclipse aufrufen: Aktualisieren Sie die vorinstallierten Werkzeu-ge und laden Sie danach alle unter dem Node Android 4.4 findbaren Pakete herunter (Bild 1).

Tam Hanna ist Autor, Trainer und Berater mit

den Schwerpunkten Webent­

wicklung und Webtechnologien.

Er bloggt sporadisch unter:

▶ www.tamoggemon.com

InhaltGoogle stellt Android 4.4 vor.

AUTOR

Page 2: 52 - webundmobile.de...52 MOBILE DEVELOPMENT 12014 Google stellt Android 4.4 vor Zwischenversion Entwicklerschaft und Auguren wurden von Google gleichermaßen kalt erwischt: Man erwartete

53

MOBILE DEVELOPMENT

1/2014

Programme ohne diese Permission dürfen ihre Einstellungen nach wie vor remanent speichern. Dazu stehen zwei Ordner bereit, deren Pfade von den Methoden getExternalFilesDir und getExternalCacheDir() zurückgegeben werden.

Ausdrucken von Dokumenten

Nutzer empfinden manuelle Synchro-nisation als lästig. Mittlerweile gibt es aus diesem Grund sogar ganze Note-books, die auf Android basieren. Der Datenaustausch erfolgt dabei durch ei-nen im Hintergrund stehenden Server von Google.

Trotz aller anderslautenden Versprechungen der Drucker- und Gerätehersteller war es bis-her nicht (oder nur sehr eingeschränkt) mög-lich, diese Geräte zum Erzeugen von Hardco-pies von Dokumenten einzusetzen. Nach dem Misserfolg von Psion sah kein Anbieter von Mo-bilcomputersystemen Sinn im Entwickeln einer Druckfunktion.

Da Google mit Cloud Print und Co seit län-gerer Zeit in diesem Bereich aktiv ist, folgt mit KitKat eine Gruppe von Schnittstellen zum Ausdrucken von Dokumenten. Sofern Ihr Pro-gramm mit Bildern auskommt, ist die Vorge-hensweise dank einer Adapterklasse denkbar einfach:

private void doPhotoPrint() {PrintHelper photoPrinter = new PrintHelper(getActivity());photoPrinter.setScaleMode (PrintHelper.SCALE_MODE_FIT);Bitmap bitmap = BitmapFactory.decodeResource (getResources(),R.drawable.droids);

photoPrinter.printBitmap("Testdruck", bitmap);}

Leider bietet Google hier so gut wie keine Mög-lichkeiten zum Eingriff in das Verhalten des Drucker-Subsystems. Sie dürfen festlegen, ob die Inhalte zwecks besserer Füllung der Seite beschnitten (SCALE_MODE_FILL) oder unter Inkaufnahme von Whitespace herunterskaliert werden. SCALE_MODE_FILL. printBitmap ver-langt zudem einen String, der den Namen des Druckjobs spezifiziert.

Das Rendern von zu druckenden Inhalten in Bilder hat im Mobilbereich Tradition: Die in Ja-pan allgegenwertigen Purikura-Booths (Bild 2) lassen sich nur auf diese Art und Weise mit In-halten versorgen.

Viele Prozesse liefern als Rückgabewert ei-ne Webseite zurück, die in einer Webview ange-zeigt wird. Auch hier bietet Google eine Hilfs-methode an, die das Ausdrucken der HTML-Da-tei erleichtert (Listing 1).

Wichtig ist, dass Sie auch hier keine Mög-lichkeit zur Beeinflussung des Druckergebnis-ses haben. In der CSS-Datei getroffene Fest- ▶

Die Verwendung von Android 4.4 setzt die aktuellste Version der SDK-Tools voraus (Bild 1)

Die auch in Europa verbreiteten Bluetooth-Fotoprinter – hier ein ornamentales japanisches Gerät – erlauben das Ausdrucken von Bildern per Bluetooth (Bild 2)

private void createWebPrintJob(WebView webView) {

PrintManager printManager = (PrintManager) getActivity() .getSystemService(Context.PRINT_SERVICE);

PrintDocumentAdapter printAdapter = webView.createPrintDocumentAdapter();

String jobName = getString(R.string.app_name) + " Document"; PrintJob printJob = printManager.print(jobName, printAdapter, new PrintAttributes.Builder().build());

}

LISTING 1: CREATEWEBPRINTJOB

Quel

le: W

ikim

edia

Com

mon

s /

pixe

lms

Page 3: 52 - webundmobile.de...52 MOBILE DEVELOPMENT 12014 Google stellt Android 4.4 vor Zwischenversion Entwicklerschaft und Auguren wurden von Google gleichermaßen kalt erwischt: Man erwartete

54

MOBILE DEVELOPMENT

1/2014

legungen (Stichwort: Landscape Mode) wer-den von der Engine ignoriert, der Druckbereich lässt sich nicht festlegen. Besonders ärgerlich ist, dass Sie keine Seitenzahlen ausdrucken können. Für längere Inhalte ist diese Methode daher nur schlecht geeignet.

Fortgeschrittenes Drucken

Die hier gezeigten Hilfsmethoden sind für all jene Entwickler ideal, die ihren Kunden mit möglichst wenig Aufwand ein druckendes Pro-gramm präsentieren möchten. Anbieter von Of-fice-Suiten und anderen komplexen Produkten

möchten meist in den Druckprozess eingreifen. In diesem Fall schlägt die Stunde des komplet-ten Print-API.

Dieses erlaubt Ihnen das Einreichen von aus-zudruckenden Inhalten im PDF-Format. Zur Erleichterung der Datenerzeugung gibt es eine Hilfsklasse, die das Hantieren mit den PDF-Bi-närdaten überflüssig macht.

Die eigentliche Intelligenz des Druckvor-gangs findet sich in einem Print-Adapter. Dabei handelt es sich um eine von PrintDocumentAdap­ter abgeleitete Klasse (Listing 2).

In onLayout erfolgt die Ermittlung der Länge des Druckauftrags. Das Betriebssystem versorgt die Funktion mit Informationen über die Größe des zu verwendenden Papiers und erwartet als Rückgabewert eine Instanz von PrintDocument­Info. Die eigentliche Verarbeitung der Daten er-folgt in der Funktion onWrite. Sie hat die Auf-gabe, die Inhalte in Richtung des Druckstacks zu schieben.

onStart und onFinish sind optionale Conve-nience-Methoden, die von Google primär für Housekeeping-Zwecke vorgesehen sind. Sie die-nen zum Anlegen oder Abtragen eines Schnapp-schusses der zu bearbeitenden Daten. Falls das (wie in unserem Fall) nicht notwendig ist, kön-nen Sie die Methoden in Ihrer Implementierung ohne Probleme leer lassen.

Im Hauptprogramm müssen Sie das Betriebs-system über die Druckabsicht informieren und den für die Verarbeitung notwendigen Stack zu-sammenklicken:

@Overridepublic void onClick(View v) { PrintManager printManager = (PrintManager) this.getSystemService (Context.PRINT_SERVICE); String jobName = "NMG-Testdruck"; NMGPrintAdapter anAdapter=new NMGPrintAdapter(); anAdapter.myMainActivityRef=this; printManager.print(jobName, anAdapter ,null); }

Nach dem Beschaffen einer Referenz auf den Print-Manager legen wir den in der Benutzer-schnittstelle anzuzeigenden Jobnamen fest und erstellen eine Instanz des PrintAdapters. Da-nach folgt ein Aufruf von print, der den eigentli-chen Druckprozess anstößt.

Druckmethoden implementieren

Nach dem Aufbau der Grundstruktur ist es nun an der Zeit, die eigentliche Logik zu realisie-ren. Unser vergleichsweise primitives Beispiel

public class NMGPrintAdapter extends PrintDocumentAdapter{

@Override public void onStart() { // TODO Auto-generated method stub super.onStart(); } @Override public void onFinish() { // TODO Auto-generated method stub super.onFinish(); } @Override public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras) { // TODO Auto-generated method stub } @Override public void onWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback) { // TODO Auto-generated method stub }

}

LISTING 2: NMGPRINTADAPTER

// Draw page content for printingCanvas canvas = page.getCanvas();int titleBaseLine = 72;int leftMargin = 54;

Paint paint = new Paint();paint.setColor(Color.BLACK);paint.setTextSize(36);canvas.drawText("Titel ist HIER", leftMargin, titleBaseLine, paint);paint.setColor(Color.BLUE);canvas.drawRect(100, 100, 172, 172, paint);// Rendering is complete, so page can be finalized.myPdfDocument.finishPage(page);}

LISTING 3: CANVAS

Page 4: 52 - webundmobile.de...52 MOBILE DEVELOPMENT 12014 Google stellt Android 4.4 vor Zwischenversion Entwicklerschaft und Auguren wurden von Google gleichermaßen kalt erwischt: Man erwartete

55

MOBILE DEVELOPMENT

1/2014

käme mit weitaus we-niger aus. Aus didak-tischen Gründen sind die hier gezeigten Me-thoden näher am Voll-ausbau:

@Overridepublic void onLayout(Print Attributes oldAttributes, PrintAttributes newAttributes,CancellationSignal cancellationSig-nal, LayoutResult-Callback callback, Bundle extras) {

OnLayout bekommt fünf Parameter mit. Old Attributes und new­Attributes enthalten In-formationen über das alte und neue Aussehen des für die Ausgabe zu verwendenden Papiers.

Die angelieferten Attribute nutzen wir außer-dem zum Erstellen einer Instanz von myPdfDo­cument. Diese Klasse enthält die eigentlichen Druckdaten, die in onWrite generiert werden:

myPdfDocument = new PrintedPdfDocument(myMainActivityRef, newAttributes);

Bei parallelisierten Druckvorgängen stellt sich für das System die Frage, wie es den Druckvor-gang terminieren kann. Google löst dieses Prob-lem durch das Übergeben des cancellationSignal-Objekts. In lang laufenden Layout-Operationen sollten Sie seine isCanceled-Methode regelmäßig prüfen, um das verbleibende Interesse des Nut-zers abzuschätzen:

if (cancellationSignal.isCanceled() ) { callback.onLayoutCancelled(); return;}

Im newAttributes-Feld finden Sie unter anderem die MediaSize-Klasse. Diese bietet Ihnen diver-se Informationen über die Seitengröße und das ausgewählte Papierformat. In unserem Fall nut-zen wir eine eher primitive Logik zur Ermitt-lung der für den Ausdruck nötigen Seitenzahl:

int itemsPerPage = 1;MediaSize pageSize = newAttributes.getMediaSize();

if (!pageSize.isPortrait()) { itemsPerPage = 2;}int printItemCount = 2;

myPages=(int) Math.ceil (printItemCount / itemsPerPage);

Zu guter Letzt müssen Sie den Druck-Manager über die Ergebnisse des Layout-Prozesses infor-mieren. Dazu nutzen Sie die Methoden der call­back-Klasse. Diese lassen sich auch aus einem im Hintergrund ablaufenden Thread abfeuern, was das Erstellen von schnell reagierenden Anwen-dungen erleichtert.

onLayoutFinished verlangt über die neuen Di-mensionen hinaus auch ein bool-Flag, das das System über das Vorliegen von Neuigkeiten in-formiert:

if (myPages > 0) { PrintDocumentInfo info = new PrintDocumentInfo.Builder ("print_output.pdf").setContentType (PrintDocumentInfo. CONTENT_TYPE_DOCUMENT). setPageCount(myPages).build(); callback.onLayoutFinished(info, true);} else { callback.onLayoutFailed("Page ▶

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/container" > <View android:layout_width="100dip" android:layout_height="50dip" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:background="#f00" android:id="@+id/view1"/>

<View android:layout_width="100dip" android:layout_height="50dip" android:layout_alignParentTop="true" android:layout_alignParentRight= "true" android:background="#0f0" android:id="@+id/view2"/>

</RelativeLayout>

LISTING 4: XML (SZENE 1)

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/container" > <View android:layout_width="100dip" android:layout_height="50dip" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:background="#0f0" android:id="@+id/view2"/>

<TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_ alignParentRight= "true" android:layout_alignParentTop="true" android:layout_marginTop="14dp" android:text="TextView" />

</RelativeLayout>

LISTING 5: XML (SZENE 2)

Page 5: 52 - webundmobile.de...52 MOBILE DEVELOPMENT 12014 Google stellt Android 4.4 vor Zwischenversion Entwicklerschaft und Auguren wurden von Google gleichermaßen kalt erwischt: Man erwartete

56

MOBILE DEVELOPMENT

1/2014

count calculation failed.");}

Das eigentliche Drucken erfolgt sodann in on­Write:

@Overridepublic void onWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback) {

Android erlaubt dem Benutzer das flexible Fest-legen des auszudruckenden Bereichs. Ihre on­Write-Funktion erhält aus diesem Grund eine Gruppe von PageRange-Objekten, die Sie über

den Beginn und das Ende des jeweiligen Druck-bereichs informieren:

for (int i = 0; i < myPages; i++) { PdfDocument.Page page = myPdfDocument.startPage(i); // check for cancellation if (cancellationSignal.isCanceled()) { callback.onWriteCancelled(); myPdfDocument.close(); myPdfDocument = null; return; }

Die normalerweise an dieser Stelle nötige manu-elle Erstellung des PDF-Markups entfällt, da ei-ne PDFDocument-Page-Instanz eine getCanvas-Methode anbietet. Diese liefert einen normalen Graphics Canvas zurück, der das Erstellen der auszudruckenden Daten ermöglicht.

Hierbei ist wichtig, dass der Canvas das Plat-zieren von Elementen direkt am Rand des Pa-piers erlaubt. Viele Drucker kommen damit nicht zurecht, was von Seiten des Canvas aus aber nicht angemeldet wird (Listing 3).

Zu guter Letzt müssen die generierten Daten noch an das System zurückgegeben werden. Da-zu öffnen Sie die als destination übergebene Da-tei und versehen sie mit den notwendigen In-formationen. Danach folgt noch ein Aufruf des Callbacks, um Android über den erfolgreichen Ausdruck zu informieren:

try { myPdfDocument.writeTo(new FileOutputStream

<RelativeLayout xmlns:android= "http://schemas.android.com/apk/res/android"...tools:context=".MainActivity" >

<LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_marginTop="48dp" >

<Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Szene 1" />

<Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content"

android:text="Szene 2" /> <Button android:id="@+id/button3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Eigene S." />

</LinearLayout> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/sceneRoot">

<include layout="@layout/scene1"/>

</LinearLayout>

</RelativeLayout>

LISTING 6: FORMULAR

public class MainActivity extends Activity { Scene myScene1, myScene2; ViewGroup mySceneRoot; TransitionManager myTransitionManager;

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mySceneRoot = (ViewGroup) findViewById(R.id.sceneRoot); myScene1 = Scene.getSceneForLayout(mySceneRoot, R.layout.scene1, this); myScene2 = Scene.getSceneForLayout(mySceneRoot, R.layout.scene2, this); myTransitionManager = new TransitionManager(); }

LISTING 7: MAINACTIVITY

Page 6: 52 - webundmobile.de...52 MOBILE DEVELOPMENT 12014 Google stellt Android 4.4 vor Zwischenversion Entwicklerschaft und Auguren wurden von Google gleichermaßen kalt erwischt: Man erwartete

57

MOBILE DEVELOPMENT

1/2014

(destination.getFileDescriptor()));} catch (IOException e) { callback.onWriteFailed( e.toString()); return;} finally { myPdfDocument.close(); myPdfDocument = null;}PageRange myRange=new PageRange(0, myPages-1);PageRange[] myRangeArray= new PageRange[1];myRangeArray[0]=myRange;callback.onWriteFinished(myRangeArray);}

Theoretisch spräche nichts dagegen, die Erstel-lung des PDFs mit einer anderen Bibliothek zu erledigen. Auf langsamen Telefonen kann die Verarbeitung des Druckauftrags zudem zu ei-ner der berüchtigten ANR-Meldungen führen. In diesem Fall ist es ratsam, auf einen AsyncTask zurückzugreifen.

Animationen aus der Dose

Wer eine Cascades-Applikation erstellt, be-kommt von Haus aus eine Gruppe von Über-gangseffekten an die Hand. Der mit KitKat ein-geführte Transition-Manager versucht, dieses Konzept auf Android zu übersiedeln. Die dahin-terstehende Idee ist, dass die Benutzerschnitt-stelle Ihres Programms in sogenannte Szenen unterteilt wird. Eine neue Programmierschnitt-stelle sorgt sodann dafür, dass die Übergänge zwischen den einzelnen Szenen mit diversen Animationen versehen werden.

Normalerweise bestehen Szenen aus Formu-laren. Das muss allerdings nicht immer sein: Es ist möglich und legitim, Gruppen von Steuerele-menten in eine Szene zusammenzufassen. Zwi-schen den Szenen schreiben Sie danach Transi-tionen, die die Übergänge spezifizieren. Das Aufrufen des Transition-Managers sorgt dafür, dass die Übergänge animiert werden. Neben dem Verwenden der Stock-Animationen dürfen Sie auch eigene Übergangseffekte spezifizieren.

Nach diesen einleitenden Überlegungen ist es an der Zeit, ein kleines Beispiel zusammenzu-bauen. Es soll zwischen zwei verschiedenen For-mularinhalten wechseln. Dazu benötigen wir zwei Ressourcen-Dateien, die die Widgets ent-halten. Die auf Layouts basierenden XML-Datei-en enthalten keine besondere Intelligenz. In Sze-ne eins finden sich nur zwei durch View-Instan-zen realisiert farbige Quader (Listing 4).

Der Inhalt der zweiten Szene ist für die Pro-grammausführung selbst von keiner besonde-ren Bedeutung. Aus didaktischen Gründen fin-det sich jedoch auch hier einer der Quader wie-der, als zweites Widget dient diesmal eine Text-box (Listing 5).

Zudem ist noch ein Mutter-Formular erfor-derlich, in dem sich die beiden weiter oben ge-zeigten Szenen anordnen (Listing 6).

Seine Struktur besteht aus einer Gruppe von Layouts mit drei Buttons und einem weiteren LinearLayout, das als Basis für die anzuzeigen-den Szenen dient. Die Include-Anweisung sorgt dafür, dass das Formular gleich nach dem Pro-grammstart brauchbare Daten enthält.

Im nächsten Schritt müssen wir die Szenen er-stellen. Das geschieht in der onCreate-Methode der Activity. Die für das Laden zuständige Me-thode getSceneForLayout erkennt automatisch, dass sie hier ein Layout-XML einliest (Listing 7).

Google bietet die Scene-Klasse mit zwei leicht unterschiedlichen Konstruktoren an. Der erste der beiden nimmt nur eine ViewGroup als Para-meter entgegen. Die darin enthaltenen Elemente wandern im Ernstfall auf den Bildschirm.

Die hier verwendete Methode Nummer zwei verlangt ein Wurzel- und ein Additionsobjekt. Beim Aktivieren einer so aufgebauten Scene ent-fernt das Framework im ersten Schritt alle in der Wurzel enthaltenen Widgets und ersetzt sie da-nach durch die im Additionsobjekt enthaltenen Elemente.

Damit fehlt uns nur mehr das eigentliche An-stoßen der Übergänge.

public void onClick(View arg0) { if(arg0==myButton1) { myTransitionManager.go(myScene1); } else if(arg0==myButton2) { myTransitionManager.go(myScene2); }}

go() sorgt dafür, dass der Transition-Manager die angewiesene Scene mit der Default-Transak-tion auf den Bildschirm holt. Im Fall eines Wech-sels von Scene1 auf Scene2 bekommen wir es da-bei mit einer vierstufigen Animationsfolge zu tun, die in Bild 3 und Bild 4 zu sehen ist.

Transaktion nach Maß

Unser soeben erstelltes Beispiel lässt den Benut-zer zwischen den Formularinhalten hin- und herwechseln. Dabei kommen die von Google vordefinierten Animationen zum Einsatz. In der Praxis ist das oft nicht ausreichend. Der ein-fachste Weg zum Anpassen des Verhaltens ist das Parametrieren des Transition-Managers. ▶

Am Anfang steht der rote Quader links, der grüne Quader ist rechts (Bild 3)

Während des Übergangs verschwin-det der rote Quader. Danach rutscht der grüne Quader nach rechts. Im letzten Schritt erscheint die Textbox per Fade-in (Bild 4)

Page 7: 52 - webundmobile.de...52 MOBILE DEVELOPMENT 12014 Google stellt Android 4.4 vor Zwischenversion Entwicklerschaft und Auguren wurden von Google gleichermaßen kalt erwischt: Man erwartete

58

MOBILE DEVELOPMENT

1/2014

Dies lässt sich sowohl durch eine XML-Datei als auch durch Code erledigen. Für unser klei-nes Beispiel wollen wir auf XML setzen. Das da-zu notwendige Markup sieht so aus:

<transitionManager xmlns:android="http://schemas.android.com/apk/res/android">

<transition android:fromScene= "@layout/scene1" android:toScene="@layout/scene2" android:transition="@transition/ changebounds_fadeout_sequential"/>

<transition android:fromScene= "@layout/scene2" android:toScene="@layout/scene1" android:transition="@transition/ changebounds_fadein_together"/>

</transitionManager>

TransactionManager-XML-Konstrukte bestehen normalerweise aus drei Elementen. FromScene und toScene legen fest, welche Szenenänderun-gen die jeweiligen Übergänge auslösen.

Der transition-Parameter erwartet seinerseits Verweise auf weitere XML-Dateien, die die Ani-mationseffekte weiter beschreiben. In unserem Fall handelt es sich dabei um zwei verschiede-ne Effektdateien – die erste realisiert einen syn-chron ablaufenden Fade-Effekt:

<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"> <changeBounds/> <fade android:fadingMode="fade_in" > <targets> <target android:targetId= "@id/view2" />

</targets> </fade></transitionSet>

Unser TransitionSet besteht aus zwei vonei-nander unabhängigen Effekten. Der Change-Bounds-Übergang realisiert den Morphing-Ef-fekt, während die view2 durch einen Fade-Ef-fekt bearbeitet wird.

In der zweiten Effektdatei entsteht eine se-quenzielle ChangeBounds-Animation:

<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"android:transitionOrdering= "sequential"> <changeBounds/> <fade android:fadingMode= "fade_out" > <targets> <target android:targetId= "@id/view2" /> </targets> </fade></transitionSet>

Durch das Setzen des transitionOrdering-Para-meters wird das System zur sequenziellen Abar-beitung der Befehle angewiesen. Die view2 ver-schwindet per FadeOut vom Bildschirm.

Die im Verzeichnis /transition/ liegenden Da-teien lösen unter Umständen einen invalid re­source directory name-Fehler aus. Dieser deutet darauf hin, dass ein Teil der Toolchain mit dem neu eingeführten Ressourcentyp nicht zurecht-kommt. Als Erstes sollten Sie in diesem Fall prü-fen, ob alle Komponenten der Toolchain auf dem aktuellsten Stand sind. Nachteilig ist hier, dass sich die Build-Tools oft nicht automatisch mitak-tualisieren. In diesem Fall müssen Sie die aktu-ellste Version der Werkzeuge mit dem Android SDK Manager nachinstallieren. Bild 5 zeigt eine nicht funktionsfähige Konfiguration.

Nach der Aktualisierung der Developer Tools müssen Sie Ihr Projekt noch zum Verwenden der neuen Version animieren. Dazu genügt es normalerweise, die IDE neu zu starten. Im Rah-men des Reboots sucht sich das Plug-in auto-matisch die aktuellste Version der Build-Tools. Wenn auch dies nicht zum Erfolg führt, so hilft ein Rechtsklick auf das Projekt im Package-Ex-plorer. Im daraufhin erscheinenden Kontextme-nü wählen Sie dann die Option Android Tools, Fix Project Properties.

Im Rahmen von onCreate versehen wir den TransitionManager mit der in der XML-Datei befindlichen Intelligenz:

TransitionInflater inflater = TransitionInflater.from(this);

Hier fehlen die aktuellsten Build Tools – die Kompilation schlägt fehl (Bild 5)

Der rote Quader wächst und wächst (Bild 6)

Nach einem Klick auf Go Immersive verschwindet die Statusleiste – das Touch-Handling bleibt davon unbe-rührt und läuft weiter (Bild 7)

Page 8: 52 - webundmobile.de...52 MOBILE DEVELOPMENT 12014 Google stellt Android 4.4 vor Zwischenversion Entwicklerschaft und Auguren wurden von Google gleichermaßen kalt erwischt: Man erwartete

59

MOBILE DEVELOPMENT

1/2014

myTransitionManager = inflater.inflateTransitionManager(R.transition.transitions_mgr, mySceneRoot);

Damit sind wir am Ziel angekommen. Der Wechsel zwischen den Szenen erfolgt fortan durch das Anstoßen des Transition-Managers. Der dazu vorgesehene Code entspricht eins zu eins dem im vorigen Codebeispiel verwendeten.

Unter Umständen reichen die hier gezeigten Ausblend- und Positionsveränderungsmetho-den nicht aus. Dann empfiehlt es sich, das Ver-halten der einzelnen Steuerelemente von Hand zu bestimmen. Hier implementieren wir dies in einem speziellen Button mit folgendem Code:

TransitionManager. beginDelayedTransition(mySceneRoot);View view = findViewById(R.id.view1);ViewGroup.LayoutParams params = view.getLayoutParams();params.width = 200;params.height = 100;view.setLayoutParams(params);

An dieser Stelle findet sich eine kleine Besonder-heit. Der Aufruf von beginDelayedTransition ver-setzt den TransitionManager in Lauerstellung – alle folgenden Veränderungen werden automa-tisch animiert (Bild 6).

Kleinigkeiten sind wichtig

Seit dem iPhone sind Benutzer darauf trainiert, das Interface ihres Telefons genau unter die Lu-pe zu nehmen. Unter Android war die immer sichtbare Statusleiste ein Ärgernis, das die Ent-scheidungsfreiheit des Designers beschränkte.

Hinter den Stichworten Immersive Mode und Translucent System UI verbergen sich zwei Funk-tionen, die an dieser Stelle Abhilfe versprechen. Die Verwendung des Fullscreen-Modus erfolgt durch das Übergeben von zwei Flags an die Funktion setSystemUIVisibility. Die verschiede-nen Kombinationen sind in der folgenden Rou-tine demonstriert (Bild 7) :

@Overridepublic void onClick(View arg0) { if(arg0==myButton1) { arg0.setSystemUiVisibility (View.SYSTEM_UI_FLAG_HIDE_ NAVIGATION | View.SYSTEM_UI_FLAG_ IMMERSIVE| View.SYSTEM_UI_FLAG_ FULLSCREEN); } ... }

Die Verwendung von setSystemUiVisibility setzt eine Referenz auf eine am Bildschirm befindli-

che View voraus. Dabei muss es sich nicht unbedingt um das Root-Element handeln. In unserem Fall ergreifen wir die an den onClick-Handler übergebe-ne Referenz auf den soeben angeklick-ten Button.

Bisher implementierte jeder Ent-wickler sein eigenes Fullscreen-API. Zur Beendigung der Vollbildanzeige kamen diverse Gesten zum Einsatz, was auf Seiten der Benutzer zu Frus-tration führte. KitKat führt hier eine standardisierte Vorgehensweise ein: ein Wisch von oben nach unten sorgt dafür, dass die diversen Navigations-elemente erscheinen.

Im Normalfall bleiben diese danach sichtbar. Wenn Sie die Statusleiste nur kurz aufblitzen lassen möchten, so übergeben Sie stattdessen wie im folgenden Snippet gezeigt IMMERSI­VE_STICKY:

@Overridepublic void onClick(View arg0) { ... else if(arg0==myButton2) { arg0.setSystemUiVisibility (View.SYSTEM_UI_FLAG_HIDE_ NAVIGATION | View.SYSTEM_UI_FLAG_ IMMERSIVE_STICKY | View.SYSTEM_ UI_FLAG_FULLSCREEN); }}

Manchmal ist es nicht wünschenswert, die in der Statusleiste angebotenen Informationen kom-plett vom Bildschirm zu verbannen. Dann emp-fiehlt sich die Verwendung der neuen Themes Theme.Holo.NoActionBar.TranslucentDecor und Theme.Holo.Light.NoActionBar.TranslucentDecor, die im Zusammenspiel mit der Eigenschaft fits­SystemWindows für eine transparente Darstel-lung des Hintergrunds der Statusleiste sorgen.

Neuigkeiten in Sachen SMS

Das Entwickeln von SMS-Applikationen war unter Android bisher nur unter Nutzung von versteckten APIs möglich. KitKat bringt eine of-fizielle Programmierschnittstelle mit, die mit der bisher verwendeten komplett inkompatibel ist. Dieser vergleichsweise radikale Schritt wird von Google mit Sicherheitsbedenken begründet: Das verdeckte Versenden von SMS an Mehr-wertnummern sorgt bei den Entwicklern von Malware für gute Einnahmen.

Im Grunde genommen folgt das neue Sys-tem der Regel, dass jedes beliebige Programm auf eingehende Nachrichten reagieren darf. ▶

Ein Nook kann keine SMS versenden (Bild 8)

Process Stats bietet diverse Informationen über die Speicher-

auslastung an (Bild 9)

Page 9: 52 - webundmobile.de...52 MOBILE DEVELOPMENT 12014 Google stellt Android 4.4 vor Zwischenversion Entwicklerschaft und Auguren wurden von Google gleichermaßen kalt erwischt: Man erwartete

60

MOBILE DEVELOPMENT

1/2014

Das Versenden von Kurznachrichten ist der Ap-plikation vorbehalten, die vom Nutzer als Stan-dard-SMS-Programm auserkoren wurde. Das erfolgt in einem Systemdialog. Wenn Sie Ihr Pro-dukt in der dort angezeigten Liste aufnehmen möchten, so müssen Sie eine Gruppe von Broad-cast-Receivern implementieren.

Der erste der erforderlichen Intent-Filter hört auf den String android.provider.Telephony.SMS_DELIVER. Er tritt immer dann in Aktion, wenn eine SMS eingeht. Ankommende MMS-Nach-richten wandern stattdessen in android.provi­der.Telephony.WAP_PUSH_DELIVER. Die Unter-

scheidung zwischen MMS und klassi-schen WAP-Push-Nachrichten erfolgt durch Auswertung des MIME-Types.

Während der Laufzeit müssen Sie prüfen, ob Ihr Programm als Default-Applikation festgelegt ist. Ist das nicht der Fall, können Sie den Nutzer zum Ändern seiner Auswahl animieren. Dazu empfiehlt es sich, Code nach dem folgenden Schema einzusetzen:

Intent intent = new Intent(context, Sms.Intents.ACTION_CHANGE_DEFAULT);intent.putExtra(Sms.Intents.EXTRA_PACKAGE_NAME, context.getPackageName());

startActivity(intent);

Der folgende Befehl verrät Ihnen weitere Infor-mationen über die als Default festgelegte Appli-kation. Vergleichen Sie den zurückgegebenen Paketnamen mit dem Ihrer Applikation, um die Rolle Ihres Produkts festzustellen:

String defaultSmsApp = Telephony.Sms.getDefaultSmsPackage(context);

Im Rahmen der Verbreitung von Smart-TVs gab es kaum einen Hersteller, der der Versuchung wiederstehen konnte, eine hauseigene Fern-steuerungssoftware anzubieten. Trotzdem ge-hört das Vorhandensein einer Infrarotschnitt-stelle im HiFi-Bereich zum guten Ton: Es gibt kaum ein Gerät, das sich nicht per IR anspre-chen lässt.

Leider wurden die in der Anfangszeit der Handcomputertechnik weit verbreiteten Infra-rotschnittstellen im Lauf der Zeit fast vollstän-dig verdrängt. HTC und Samsung begannen erst vor wenigen Monaten damit, ihre Topge-räte mit sogenannten IR-Blastern auszustatten. Dabei handelt es sich um spezielle Transmitter, die auf hohe Reichweite spezialisiert sind. Die in KitKat eingeführte ConsumerIrManager-Klas-se erlaubt Ihnen das Versenden von Informa-tionen unter Nutzung dieser Transmitter. Die Übertragung erfolgt durch das Ein- und Aus-schalten einer mit einer gewissen Frequenz ar-beitenden Infrarotdiode (Listing 8).

Kommunikation per Infrarot lässt sich am Ein-fachsten anhand einer Toolchain beschreiben. Auf der linken Seite findet sich ein Schwing-kreis, der die Stromversorgung der Lampe in ei-ner gewissen, als Trägerfrequenz bezeichneten Reihenfolge ein- und ausschaltet. Diese dient den verschiedenen Geräten zum Erkennen der ihnen zugehörigen Gegenstelle. Die eigentliche Kommunikation erfolgt erst im zweiten Schritt: Das Tor schaltet die Verbindung zwischen Lam-pe und Anreger je nach Bedarf ein und aus. Da-durch entsteht ein Paket von Ein- und Auszei-ten, die auf Seiten des Empfängers gelesen wer-den können.

Mit diesem Wissen können wir uns an die weiter oben gezeigte Routine heranwagen. Nach dem Beschaffen einer Instanz des Consumer IR Managers prüfen wir, ob unser Telefon auch wirklich über die zum Versenden von Infrarot-signalen notwendige Hardware verfügt. Ist die-se am Platz, so prüfen wir die von der Hardware unterstützten Trägerfrequenzen.

Zu guter Letzt folgt der eigentliche Versand der Daten. Die dafür zuständige Methode ver-langt eine Trägerfrequenz und ein Array mit Zeitinformationen. Das Array wird Schritt für Schritt abgearbeitet: Die Diode leuchtet für arr[0] Millisekunden, und wird danach für arr[1] abge-schaltet. Mit arr[2*i] und arr[1+2*i] wird nach demselben Schema verfahren. Die Gesamtlän-ge der Sequenz darf zwei Sekunden keinesfalls überschreiten.

Das Empfangen von Daten per Infrarot ist im Moment nicht Teil der Spezifikation. Es ist da-von auszugehen, dass die meisten Smartphones die dazu notwendige Hardware schlicht nicht mitbringen – wozu auch, es gibt ja kaum mehr per IR kommunizierende Geräte.

Die Play Services spawnen eine Vielzahl von Services, die Rechenleistung und Speicher verbrauchen (Bild 10)

public void onClick(View v) { ConsumerIrManager myManager=(ConsumerIrManager) getSystemService(CONSUMER_IR_SERVICE); if(myManager.hasIrEmitter()) { CarrierFrequencyRange[] myRange = myManager.getCarrierFrequencies(); int myPatternArray[] = new int[6]; myPatternArray[0]=1000; //1000 Mikrosekunden an myPatternArray[1]=1000; //1000 Mikrosekunden aus myPatternArray[2]=1000; myPatternArray[3]=1000; myPatternArray[4]=1000; myPatternArray[5]=1000; myManager.transmit(myRange[0].getMinFrequency(), myPatternArray); }}

LISTING 8: CONSUMERIRMANAGER

Page 10: 52 - webundmobile.de...52 MOBILE DEVELOPMENT 12014 Google stellt Android 4.4 vor Zwischenversion Entwicklerschaft und Auguren wurden von Google gleichermaßen kalt erwischt: Man erwartete

61

MOBILE DEVELOPMENT

1/2014

Nutzer haben die unangenehme Eigenschaft, mit ihrer Hardware aus technischen Gründen inkompatible Produkte schlecht zu bewerten. Die Bewertung des IM-Programms GottaTxt beispielsweise erfolgte von einer Nutzerin, de-ren Hardware in Ermangelung eines GSM-Mo-dems zum Versand von Kurznachrichten unfä-hig war (Bild 8).

Am einfachsten lassen sich derartige Rache-bewertungen verhindern, wenn Sie inkompati-ble Hardware von vornherein ausschließen. Da-zu genügt es, das Feature FEATURE_CONSU­MER_IR zwingend vorauszusetzen.

Achtung, Speichermangel

Im High-End-Bereich gehören unter Android 2 GByte Speicher mittlerweile zum guten Ton – es gibt kaum ein vierkerniges System, das mit weniger als 1 GByte RAM auskommen muss. Im Low-End-Bereich sieht die Sache komplett an-ders aus: Wenn jeder Cent zählt, ist eine Halbie-rung des Arbeitsspeicherausbaus eine wesentli-che Erleichterung für den OEM.

Mozillas Firefox OS lebt von dieser Schwä-che. Die Erfolge in Lateinamerika entstanden auf Hardware, die für Android 4.3 nicht oder nur sehr leidlich ausreicht. Um dem ehemali-gen Protege in Entwicklungs- und Schwellen-ländern das Feld nicht kampflos zu überlassen, wurde Android 4.4 auf Telefone mit nur 512 MByte RAM optimiert.

Um Entwicklern das Anpassen ihrer Produk-te zu erleichtern, spendiert Google eine Grup-pe von neuen Werkzeugen und eine neue Funk-tion. Im ActivityManager finden Sie die Metho-de isLowRamDevice, die Informationen über die Klasse des Speicherausbaus bietet.

Leider ist die Spezifikation der Funktionswei-se alles andere als genau. In der Dokumenta-tion findet sich nur die folgende, etwas lapidare Aussage: »Returns true if this is a low-RAM de-vice. Exactly whether a device is low-RAM is ul-timately up to the device configuration, but cur-rently it generally means something in the class of a 512MB device with about a 800x480 or less screen. This is mostly intended to be used by apps to determine whether they should turn off certain features that require more RAM.«

Schon allein aufgrund des geringen Preises eines Low-End-Geräts ist es ratsam, pro Stand-ort des Unternehmens ein solches anzuschaffen. Die billige Verarbeitung und der kontrastarme Bildschirm machen die eine oder andere zusätz-liche Anpassung notwendig, die ein reiner Test im Emulator nicht zu Tage fördert.

Dabei ist die von Google neu eingeführte Speicheranalyseansicht hilfreich. Dieser unter Settings, Developer Options, Process stats findba-re Dialog präsentiert Ihnen eine Übersicht über

alle aktuell am Telefon aktiven Programme und Dienste. Die in Bild 9 gezeigte Liste zeigt die Speicherauslastung eines von Google in An-spruch genommenen Geräts.

Der farbige Balken bewertet die Systemge-sundheit über die Zeit. Der rote Teil gibt an, wie viel Prozent der Messperiode im Sonderre-gime gefahren wurde, Orange verweist auf ver-gleichsweise hohen Speicherverbrauch. Wichtig ist, dass sich diese Information auf das System als Ganzes bezieht. Weitere Informationen über Ihr jeweiliges Programm erhalten Sie, indem Sie seinen Eintrag anklicken (Bild 10).

Anhand der eingeblendeten Zahl erkennen Sie, wie viel Zeit das jeweilige Programm ak-tiv war. Im Menü finden Sie zudem eine Grup-pe von Filtern. Falls sich das Telefon nicht per-manent in Ihren Händen befindet, sollten Sie die Log-Zeit verlängern. Von Haus erfasst das Sys-tem nämlich nur die letzten drei Stunden.

Die von Process Stats angezeigten Informa-tionen erlauben einen schnellen Überblick ▶

ART beschleunigt die Aus- führung von Android-Code

wesentlich (Bild 11)

C:\Program Files\Android\android-sdk\platform-tools>adb shell dumpsys procstats* system / 1000:TOTAL: 100% (26MB-26MB-27MB/22MB-23MB-24MB over 3)Persistent: 100% (26MB-26MB-27MB/22MB-23MB-24MB over 3). . .* com.google.process.gapps / u0a6:TOTAL: 96% (9.4MB-9.6MB-9.8MB/7.4MB-7.6MB-7.8MB over 2)Imp Bg: 3.2%Service: 92% (9.4MB-9.6MB-9.8MB/7.4MB-7.6MB-7.8MB over 2)Receiver: 0.58%(Cached): 0.44%. . .

Run time Stats:Screen On / Norm / +42m31s942ms (running)TOTAL: +42m31s942ms

Start time: 2013-11-11 15:14:07Total elapsed time: +44m27s160ms (partial) libdvm.so chromeview

LISTING 9: PROCSTATS

Page 11: 52 - webundmobile.de...52 MOBILE DEVELOPMENT 12014 Google stellt Android 4.4 vor Zwischenversion Entwicklerschaft und Auguren wurden von Google gleichermaßen kalt erwischt: Man erwartete

62

MOBILE DEVELOPMENT

1/2014

über die Auslastung. Detaillierte-re Daten erhalten Sie durch die neu eingeführten beziehungswei-se verbesserten Werkzeuge proc­stats und meminfo. Beide lassen sich nach dem Schema in Listing 9 aus adb heraus aufrufen.

Ein Vergleich der Ausgabe mit den in Proc Stats ausgegebenen Daten lässt darauf schließen, dass Google hier einfach das im Hinter-grund rackernde Werkzeug expo-niert hat. Meminfo liefert detail-lierte Informationen über die von einem Prozess verbrauchte Spei-chermenge. Das vergleichsweise komplizierte Kommando ist un-ter http://developer.android.com /tools/debugging/debugging-me mory.html im Detail dokumen-tiert.

Videos nach Maß

Listings im Play Store profitieren sehr davon, wenn sie neben Screenshots auch ein kleines Vi-deo der Applikation enthalten. Bisher mussten Entwickler diese mit einer externen Kamera und einem Stativ aufzeichnen, was zu eher unbefrie-digenden Ergebnissen führte.

Das in KitKat neu eingeführte Screenrecord-Werkzeug verspricht an dieser Stelle Abhilfe. Es lässt sich per adb über den shell-Befehl ausfüh-ren (Listing 10).

Wichtig ist, dass das Programm aufgrund der Systemgegebenheiten nicht nach Belieben schal-ten und walten kann. Manche Telefone sind zu langsam, um Inhalte in ihrer nativen Bild-schirmauflösung festzuhalten. Bildschirmrota-tionen führen zu undefiniertem Verhalten und sind deshalb nicht empfehlenswert.

ART

Als Android vor vielen Jahren das Licht der Welt erblickte, fragten sich viele Entwickler nach dem Sinn der auf einer Java Virtual Machine ba-sierenden Architektur. Obwohl Google Dalvik mit diversen Performance-Optimierungen ver-sehen hat, ist die Performance des resultieren-den Codes nativem Code nach wie vor an vie-lerlei Stelle unterlegen.

Eine als Android RunTime bezeichnete En-gine soll an dieser Stelle Abhilfe schaffen. An-statt den Code wie bisher im JIT-Verfahren zu transpilieren, kommt in Zukunft ein als Ahead of Time bezeichnetes Verfahren zum Einsatz. Diese im Großen und Ganzen erprobte Vorge-hensweise basiert darauf, dass der Bytecode lan-ge vor seiner Ausführung in nativen Code ge-wandelt wird und in diesem Format auf dem Gerät liegt.

ART ist im Moment nur spärlich dokumen-tiert – unter anderem ist noch nicht bekannt, ob die Transpilation des Maschinencodes auf dem Handy, im Store oder auf der Workstation des Entwicklers erfolgt. Immerhin gibt es erste syn-thetische Benchmarks, die Performance-Steige-rungen im Bereich von 100 Prozent versprechen.

Im Moment lässt sich ART in von Hand er-stellten Builds aktivieren. Google warnt auf-grund diverser Inkompatibilitäten explizit da-vor, die Engine als Haupt-Runtime einzusetzen. Es ist noch nicht klar, wann Hardware-Herstel-ler Dalvik austauschen dürfen.

WebKit – nein danke

Aufgrund der Entwicklung von Chromium fand sich Google seit einiger Zeit in der Situa-tion, seinen Kunden zwei verschiedene Browser anzubieten. In Android selbst werkelte WebKit, während viele Nutzer ihrem Telefon durch die Installation des Chromium-basierten Chrome for Android einen zusätzlichen Performance-Schub verschafften. Ab Android 4.4 setzen al-le in Applikationen enthaltenen WebView-Steu-erelemente auf die Chromium-Engine. Obwohl das Setzen einer TargetSDKVersion kleiner 19 eine Art Quirks Mode aktiviert, müssen Sie als Entwickler trotzdem von Änderungen im Be-reich der Rendering-Engine ausgehen.

Die mit Abstand schmerzhafteste Neuerung betrifft die Handhabung von Custom-URLs.

android-sdk\platform-tools>adb shell screenrecord --helpUsage: screenrecord [options] <filename>

Records the device's display to a .mp4 file.

Options:

--size WIDTHxHEIGHTSet the video size, e.g. "1280x720". Default is the device's maindisplay resolution (if supported), 1280x720 if not. For best results, use a size supported by the AVC encoder.--bit-rate RATESet the video bit rate, in megabits per second. Default 4Mbps.--time-limit TIMESet the maximum recording time, in seconds. Default / maximum is 180.--rotateRotate the output 90 degrees.--verboseDisplay interesting information on stdout.--helpShow this message.

Recording continues until Ctrl-C is hit or the time limit is reached.

LISTING 10: SCREENRECORD

Das Aktivieren des GPU Sharings führt zu Problemen mit dem Emulator (Bild 12)

Page 12: 52 - webundmobile.de...52 MOBILE DEVELOPMENT 12014 Google stellt Android 4.4 vor Zwischenversion Entwicklerschaft und Auguren wurden von Google gleichermaßen kalt erwischt: Man erwartete

63

MOBILE DEVELOPMENT

1/2014

Bisher war es üblich, für die Engine bestimm-te Links in der WebView nach dem folgenden Schema aufzubauen:

<a href="showProfile">Show Profile</a>

Ein Klick des Nutzers führt in diesem Fall zum Aufruf der shouldOverrideURLLoading()-Call-backfunktion. Der als href übergebene Parame-ter dient zur Identifikation der aufzurufenden Seite. Leider funktioniert das unter KitKat nicht mehr, da der URL der RFC3986 nicht entspricht.

Der beste Workaround besteht darin, den String mit einem Präfix nach dem folgenden Schema zu versehen:

<a href="example-app:showProfile"> Show Profile</a>

Ist dies in Ihrem Programm aus irgendwelchen Gründen nicht realisierbar, so bietet sich die Ver-wendung von loadDataWithBaseURL() an. Diese Funktion erlaubt das nachträgliche Einschrei-ben einer gemeinsamen Webadresse, ist auf-grund ihrer Nebeneffekte aber nicht unbedingt der Weisheit letzter Schluss.

Neben diesen eher radikalen Änderungen gibt es auch eine Vielzahl kleinerer Änderungen an der Rendering-Engine, die sich auf die Darste-lung von nicht aktualisierten Inhalten auswir-ken. So versteht Chromium die Einstellungen NARROW_COLUMN und SINGLE_COLUMN nicht mehr, die Methoden getDefaultZoom() und setDefaultZoom() sind als NOP implementiert.

Chromium ist intern weitaus stärker paralelli-siert als WebKit. Zwecks Vereinfachung des In-terfaces wurde die Schnittstelle zwischen Web-View und Benutzerapplikation abgespeckt und ist nicht mehr thread-safe. Alle Aufrufe von Me-thoden einer WebView-Instanz müssen im UI-Thread erfolgen. Es empfiehlt sich, hierzu ein Runnable einzusetzen.

Remote Debugging mit Chrome

Eine genaue Liste der Änderungen am CSS-Parser finden Sie unter http://developer.andro id.com/guide/webapps/migrating.html. Da die neue Engine auch im Quirks Mode nicht al-le Funktionen der klassischen WebView unter-stützt, müssen Sie Ihre HTML-Inhalte auf je-den Fall unter Android 4.4 ansehen. Erfreuli-cherweise genügt dabei jeder beliebige Emula-tor, sofern Sie die Option Use Host GPU deakti-vieren (Bild 12).

Im Rahmen der Umstellung hat sich die Ge-schwindigkeit und die Webstandard-Unterstüt-zung der WebView wesentlich verbessert. Die kleinen, weiter oben beschriebenen Änderun-gen sind ärgerlich, aber verschmerzbar. Beson-

ders amüsant ist indes, dass die Inhalte von WebView-Widgets fortan über die von Google Chrome bekannte Remote-Debugging-Schnitt-stelle ansprechbar sind.

Leider ist dazu einiges an Vorbereitungsarbeit erforderlich. Im ersten Schritt müssen Sie Ihre Arbeitsstation mit der aktuellsten Version von Google Chrome ausstatten – Remote Debug-ging von WebViews funktioniert ab Chrome 31. Die unter https://chrome.google.com/webstore/ detail/adb/dpngiggdglpdnjdoaefidgiigpemgage erhältliche Extension muss ebenfalls auf die Workstation marschieren. Öffnen Sie den URL und klicken Sie auf den blauen Plus-Button. Am Telefon müssen Sie den Debug-Modus in den Entwickleroptionen aktivieren und das Smart-phone mit dem PC verbinden.

Aus Sicherheitsgründen lassen sich nur jene Webviews debuggen, die im Rahmen der Initi-alisierung der Anwendung als Debuggable mar-kiert werden. Das erfolgt über die statische Me-thode setWebContentsDebuggingEnabled. Wenn Sie hier true übergeben, kann eine am Desktop befindliche Chrome-Instanz Kontakt mit Ihrem Smartphone aufnehmen.

Es ist zur Steigerung der Sicherheit empfeh-lenswert, diesen Aufruf an das Vorhandensein des Debuggable­Flags zu koppeln. Nach dem ▶

public class NMGDocumentProvider extends DocumentsProvider {

@Override public ParcelFileDescriptor openDocument(String arg0, String arg1, CancellationSignal arg2) throws FileNotFoundException { // TODO Auto-generated method stub return null; } @Override Cursor queryChildDocuments(String arg0, String[] arg1, String arg2) throws FileNotFoundException { // TODO Auto-generated method stub return null; } @Override public Cursor queryDocument(String arg0, String[] arg1) throws FileNotFoundException { // TODO Auto-generated method stub return null; } @Override public Cursor queryRoots(String[] arg0) throws FileNotFoundException { // TODO Auto-generated method stub return null; } @Override public boolean onCreate() { // TODO Auto-generated method stub return false; }}

LISTING 11: DOCUMENTPROVIDER

Page 13: 52 - webundmobile.de...52 MOBILE DEVELOPMENT 12014 Google stellt Android 4.4 vor Zwischenversion Entwicklerschaft und Auguren wurden von Google gleichermaßen kalt erwischt: Man erwartete

64

MOBILE DEVELOPMENT

1/2014

Herstellen der Verbindung zwi-schen PC und Smartphone öffnen Sie am Desktop in Chrome den URL about:inspect. Das Programm zeigt Ihnen daraufhin eine grafi-sche Übersicht über alle in Ihrer Applikation befindlichen Web-Views an. Der nach einem Klick auf Inspect beginnende Debugpro-zess erfolgt mit den vom Desktop hinreichend bekannten Chrome Developer Tools.

Dropbox, Megaupload und Google Drive erfreuen sich rapi-de wachsender Beliebtheit. Es gibt

kaum einen Nutzer, der nicht zumindest ein oder zwei Konten bei diversen Cloud-Anbie-tern besitzt. Bisher war der Zugriff auf die dort befindlichen Daten alles andere als einfach: Das Herunterkopieren der Dateien musste über eine vom Anbieter realisierte Applikation erfolgen.

Ein im Rahmen des Storage Access Frame-works realisierter DocumentProvider erspart dem Benutzer diese Arbeit. Die dahinterstehen-de Logik besteht aus einem hierarchisch orga-nisierten Baumsystem, in dem ein oder mehre-re Wurzelverzeichnisse die in ihnen enthaltenen Dokumente zum Zugriff anbieten.

Jedes zurückgegebene Dokument wird durch eine Document ID identifiziert. Diese system-weit einzigartige Nummer erlaubt die Korrela-tion späterer Aufrufe mit den zu bearbeitenden Dokumenten.

Im nächsten Schritt folgt das eigentliche Er-stellen des Providers. Der Entwicklungsprozess beginnt mit dem Erstellen einer von Document-Provider abgeleiteten realen Klasse (Listing 11).

openDocument ist die wichtigste Funktion der Klasse. Sie hat die Aufgabe, das vom Benutzer

angeforderte Dokument in Form eines Parcel­FileDescriptors zurückzuliefern. Wie Sie die in dieser Klasse realisierten Lese- und Schreib-funktionen in Ihrem Provider implementieren, ist für das System nicht von Interesse.

queryRoots und queryDocument dienen zur Er-mittlung von weiteren Informationen über die im Provider enthaltenen Daten. Die Dokumen-tation empfiehlt eingehend, queryDocument aus lokalen Datenbeständen zu beantworten und auf Netzwerkzugriffe zu verzichten. Es ist da-von auszugehen, dass das Framework diese Me-thode sehr häufig aufruft.

queryChildDocuments erlaubt dem System das Abfragen des Inhalts eines Ordners. Die als Rück-gabewert verwendete Cursor-Klasse muss nicht sofort vollständig ausgefüllt werden: Wenn Sie einen Teil der Informationen erst später nachrei-chen können, so lässt sich dies über das Setzen eines Flags bewerkstelligen. Neben den hier ge-zeigten Barebones-Methoden gibt es auch eine Gruppe von weiterführenden Funktio nen. Die-se sind unter http://developer.android.com/re ference/android/provider/DocumentsProvider.html beschrieben. Zu guter Letzt muss Ihr Pro-vider noch im Applikationsmanifest registriert werden (Listing 12).

Die Permission MANAGE_DOCUMENTS kann nur vom Betriebssystem erlangt werden. Applikationen dürfen die DocumentProvider niemals direkt kontaktieren.

Auf Seiten der empfangenden Applikation ist die Implementierung geradezu primitiv. Das Absetzen eines ACTION_OPEN_DOCUMENT-Intents aktiviert die vom System vorgegebene Benutzerschnittstelle, die die Auswahl des zu verarbeitenden Files erlaubt. ACTION_CREA­TE_DOCUMENT erlaubt das Anlegen einer neuen Datei.

Fazit

In den letzten Jahren wuchs Android fast unge-bremst. Apple versperrte sich durch die Fokus-sierung auf den High-End-Markt den Zugang zur Masse, Microsoft litt unter abstrus hohen Hardwareanforderungen und der Partnerschaft mit Skype. Somit blieb den Anbietern von preis-werten Telefonen nach der Selbstausschaltung der Symbian Foundation nur die Verwendung von Googles Betriebssystem.

Am letzten Mobile World Congress änderte sich die Lage, da eine Vielzahl von neuen Platt-formen in den Markt drängen. Firefox OS ar-beitet auf Hardware flüssig, die selbst für ältere Versionen von Android eher schlecht als recht geeignet ist.

Die konsequenten Optimierungen in KitKat sorgen dafür, dass das System im Low-End-Markt weiter attraktiv bleibt. [mb]

<manifest> <application> ... <provider android:name="com.example.MyCloudProvider" android:authorities="com.example.mycloudprovider" android:exported="true" android:grantUriPermissions="true" android:permission= "android.permission.MANAGE_DOCUMENTS"> <intent-filter> <action android:name= "android.content.action.DOCUMENTS_PROVIDER" /> </intent-filter> </provider> ... </application></manifest>

LISTING 12: APPLIKATIONSMANIFEST

Das Storage Access Framework bringt eigene Dialoge mit, die den Dateizugriff erleichtern (Bild 14)