Windows 8.1 App-Entwicklung: der Weg zu ­Windows 10 01.07.2015

Alexander Jung
Alexander Jung, Chief eXpert

Windows 10 steht vor der Türe und mancher Entwickler, der sich allen Unken zum Trotz mit Windows 8 AppStore-Anwendungen auseinandergesetzt hat, wird sich fragen, was das für ihn bedeutet.

 

Es gibt da durchaus einiges Neuerungen: Universal Apps als neuer Anwendungstyp, AppStore-Anwendungen im Fenster, die Charm-Bar verschwindet.

Matthias Jauernig hat sich die Details dazu näher angeschaut. Sein Fazit:

Auch bei der Übertragung von Windows-8.1-Apps nach Windows 10 wird deutlich, dass Microsoft die klassischen Desktop-Benutzer fokussiert. Ist das schlimm? Nein! Wenn Tablet-Benutzer nicht vernachlässigt werden, ist die Ausführung von Apps in Fenstern nur zu begrüßen…

Das ist in der Tat die Crux: Microsoft muss beide Nutzergruppen bzw. –szenarien angemessen unterstützen. Mit Windows 8 hatte Microsoft zu einseitig auf Tablet-Nutzung fokussiert und den Desktop-Nutzer nicht nur ignoriert, sondern auch (mindestens gefühlt) benachteiligt. Kompromisse zugunsten eines Formfaktors dürfen aber nicht zulasten des anderen gehen. Hoffen wir, dass Microsoft das mit Windows 10 besser hinbekommt…

Share |

Xamarin Hackathon 26.06.2015

Stefan Gründig
Stefan Gründig, Chief eXpert

Hackathons sind toll. Und weil das so ist, haben der Chris, der Markus und ich (“die Organisatoren”) einen mit unseren eXperts-Kollegen abgehalten. Ziel war, unsere Erfahrungen mit Xamarin – und im speziellen Xamarin.Forms – mit den Kollegen zu teilen und sie in die Lage zu versetzen, selbst die ersten Schritte in der Cross-Plattform-Entwicklung von Mobile Apps zu gehen.

Aber was ist eigentlich ein Hackathon? Der Begriff erweckt die Assoziation einer motivierenden, ungezwungenen und dennoch zielgerichteten Arbeitsatmosphäre, die eine gute Basis ist für einen nachhaltigen Wissensaustausch unter den Kollegen. Wikipedia meint, dass es sich um eine kollaborative Software- und Hardware-Entwicklungsveranstaltung handele. Dabei werde zunächst ein Thema vorgestellt und dann dazu Umsetzungsvorschläge diskutiert. Im Folgenden werde innerhalb kurzer Zeit ein gemeinsames Produkt erstellt. In diesem umfassenden Sinne fand dies bei uns jedoch nicht statt. Wir hatten den Begriff des Hackathon etwas uminterpretiert…

Unser Hackathon hatte den Charakter eines Workshop, bei dem Wissen und Erfahrungen vermittelt werden. Die Organisatoren hatten ein Beispielprojekt entwickelt, anhand dessen die Arbeit mit Xamarin.Forms demonstriert und erfahren werden sollte. Es ging um eine Mobile App für Android, iOS und Windows Phone. Den Funktionsumfang hielten wir handlich klein, um den einen Tag, den wir für den Hackathon angesetzt hatten, nicht mit fachlichen Diskussionen vollzustopfen. Stattdessen konzentrierten wir uns auf die Technologie. Eben Xamarin.Forms. Dazu gibt es hier im Flurfunk übrigens auch den einen oder anderen Beitrag, der sich zu lesen lohnt.

Die Anforderungen an die zu entwickelnde Anwendung waren überschaubar. Sie sollte eine Liste von Elementen darstellen, welche editiert und gelöscht werden können. Auch das Hinzufügen von Elementen sollte möglich sein. Durch die Liste sollte man scrollen und im Kontext einzelner Listenelemente interagieren können. Bei der Eingabe eines Elements sollten verschiedene Tastatur-Layouts (normal, numerisch) berücksichtigt sowie einfache Validierungen durchgeführt werden.

Als Vorbereitung hatten wir eine Xamarin.Forms Solution angelegt, quasi als Referenzimplementierung, die dann während des Hackathon nach und nach aufgebaut werden sollte. Die Steps dafür hatten die Organisatoren quasi als “roten Faden” durch den Hackathon notiert. Ebenfalls im Vorfeld wurden alle Teilnehmer über die technischen Voraussetzungen informiert. So musste beispielsweise jeder Teilnehmer eine Xamarin-Trial oder -Business-Lizenz zur Verfügung haben. Weiterhin musste Xamarin auf dem Entwicklungsrechner installiert sein und geeignete Emulatoren oder Hardware Devices zum Testen bereitstehen.

Ablauf

Und so haben wir uns morgens neun Uhr zu zehnt in unserem Konferenzraum um einen Tisch versammelt, die Notebooks ausgepackt und losgelegt. Die Organisatoren sorgten per Beamer für ein gemeinsames Bild von Architektur und Code.

Zunächst stellten wir sicher, dass bei allen Teilnehmern die technischen Voraussetzungen gegeben sind. Danach ging es dem “roten Faden” folgend ans Implementieren. Dabei teilten wir den Gesamtumfang der Implementierungsschritte so auf, dass drei Leute nacheinander jeweils einen Teil davon demonstrierten. Ich legte den Grundstein für die Applikation und implementierte das architektonische Grundgerüst. Markus setzte dann fort und demonstrierte plattformspezifische Implementierungen für Windows Phone. Chris schloss daran an und vervollständigte die Applikation am Beispiel der Android-Plattform. Im Ergebnis hatten wir eine lauffähige Software mit dem geplanten Funktionsumfang auf zwei Plattformen zur Verfügung – Windows Phone und Android.

Was ist mit iOS? Dafür kann man doch mit Xamarin auch entwickeln? Selbstverständlich. Leider machte uns an diesem Tag aber Murphy einen Strich durch die Rechnung, indem er verhinderte, dass sich unser MacBook Air ins interne Netz integrierte. Damit stand es als Xamarin Build Host nicht zur Verfügung und wir konnten die iOS App zwar nebenbei mitentwickeln, aber nicht deployen und testen. Da gerade für Einsteiger in Xamarin das Entwicklungs-Setup für die Entwicklung von iOS-Applikationen besonders interessant ist, war es umso ärgerlicher, dass wir das im Hackathon nicht zeigen konnten.

Was wir gelernt haben

Am Ende des Hackathon – so gegen 16:30 – erbaten sich die Organisatoren ein Feedback von den Teilnehmern. Sozusagen was gut und was verbesserungswürdig war. Daraus ergaben sich die folgenden Erkenntnisse.

  • Was das Erklären einer laufenden Implementierung anbelangt, so ist das Zeitempfinden zwischen Teilnehmern und demjenigen, der etwas codiert, stark unterschiedlich. Demonstriert man eine Implementierung, ist man meistens zu schnell für jemanden, der dies zum ersten Mal tut und verstehen sowie nachimplementieren soll. Die Gefahr besteht, dass Teilnehmer “abgehängt” werden. Als Demonstrierender ist man von der Geschwindigkeit dann genau richtig unterwegs, wenn es einem zu langsam vorkommt.
  • Es ist aus didaktischer Sicht unbedingt empfehlenswert, zu Beginn der Veranstaltung die fertige App mit vollem Funktionsumfang vorzustellen, also das Ziel des Hackathon. Zusätzlich hilft es den Teilnehmern während der Veranstaltung dabei, die gerade durchgeführten Aktionen in den richtigen Zusammenhang zu stellen, also zu wissen, warum man gerade dieses und jenes tut.
  • Die gemeinsame Entwicklung der App teilte sich in mehrere Schritte, z. B. das Projekt-Setup, ein erstes Hallo-Welt-Beispiel, Einbinden von Ressourcen, Integration eines Dependency-Injection-Containers, Implementierung von plattformspezifischem und Shared Code. Es ist sehr hilfreich, auch vor jedem dieser einzelnen Schritte darzustellen, was das Ziel dieses Schrittes ist. Damit ist dann auch jedem klar, warum z. B. jetzt ein Interface als Abstraktion angelegt wird und was damit erreicht werden soll.
  • Um sich auf die Technologie zu fokussieren, ist es empfehlenswert, die Fachlichkeit der zu entwickelnden Anwendung klein zu halten.

Fazit

Die Technologielandschaft im Bereich der Software-Entwicklung ist bekanntermaßen immer dynamischeren Veränderungen unterworfen. Kein Mensch kann mehr in allen Themen selbst fit sein oder hat die Zeit, sich von Grund auf fit zu machen. Dafür ist das Umfeld zu komplex, zu groß die Auswahl der Technologien, zu gering die zur Verfügung stehende Zeit.

Es braucht also auch andere Wege als “Selbststudium”, um neben der eigentlichen Arbeit up-to-date zu bleiben. Wir in der SDX haben dafür bereits unterschiedliche Formate etabliert, um für Wissenstransfer innerhalb des Unternehmens zu sorgen. So halten eXperts regelmäßig zu unterschiedlichsten Themen kleine Vorträge und führen Diskussionsrunden, so am Abend, mit Pizza und Bier. Zu diesem Portfolio an Möglichkeiten der Wissensvermittlung stoßen immer mehr auch die Hackathons.

Alles in allem ist so ein Hackathon eine hervorragende Art und Weise, um noch fokussierter und intensiver Wissen zwischen eXperts auszutauschen. Und zwar hands-on, unmittelbar, praktisch, am Code. Man kann damit sehr gut Hürden abbauen, sich selbst mit neuer Technologie auseinanderzusetzen. Und die Dauer von einem ganzen Tag sorgt dafür, dass sich jeder Teilnehmende wirklich einen Tag ausschließlich der jeweiligen Thematik widmen kann.

Unsere Erfahrungen mit diesem Hackathon sind durchweg positiv. Wir haben einiges gelernt, was wir noch besser machen können. Und wer weiß, vielleicht laden wir mal zu einem öffentlichen Hackathon ein, damit auch Du mal ein bisschen SDX-Luft schuppern kannst und hoffentlich Neues mit nach Hause nimmst.

Share |

Die Affen sind los! Nachlese Developer Week 22.06.2015

Svenja Henß
Svenja Henß, Senior Assistant

3 Tage auf der Developer Week in Nürnberg liegen hinter uns und ich muss sagen – auf der DWX waren die Affen los. Smiley

Insgesamt nahmen 180 DWX Besucher an unserem Gewinnspiel teil und konnten das kniffelige Bilderrätsel lösen. Am schnellsten gelang dies in 13 Sekunden und der Gewinner konnte sich über einen Reisegutschein in Höhe von 350 Euro von Ab-in-den-Urlaub freuen.

WP_20150617_002

Außerdem wurden unter allen Teilnehmern 2 große Affen verlost.

WP_20150617_003WP_20150617_004

WP_20150617_16_12_18_ProWP_20150616_10_12_59_Pro

Wir freuen uns, dass all unsere Xamarin Affen ein neues Zuhause gefunden haben.

Einen herzlichen Dank an die zahlreichen Standbesucher für die interessanten Gespräche und das positive Feedback zu den beiden Vorträgen von Max (NFC mit Windows Phone) und Till (One Business App, Multiple Devices).

WP_20150616_10_37_19_ProFlurfunk1

Abschließend noch ein Foto eines glücklichen Gewinners. Smiley Über weitere (Affen-)Fotos von euch freuen wir uns natürlich sehr. Bitte sendet sie direkt an info@sdx-ag.de.

image2

Share |

LINQ Coding Guidelines–WrapUp

Alexander Jung
Alexander Jung, Chief eXpert

Im ersten Beitrag dieser Serie habe ich das Fehlen von Coding Guidelines für LINQ beklagt. Während wir bei bei “normalem” Code auf Diskussionen in der Vergangenheit und diverse Guidelines zurückgreifen können – von Namenskonventionen bis hin zur Frage, ob die geschweifte Klammer in eine eigene Zeile gehört – scheint es hierzu bei LINQ nicht einmal eine Auseinandersetzung zu geben.

 

Mit meinen Beiträgen habe ich versucht, zunächst die Notwendigkeit zu beschreiben (”Error not found”) und einige Klarstellungen vorwegzuschicken (Definition). Die konkreten Guidelines sind nicht das Ergebnis theoretischer Überlegungen, sondern basieren auf realen Beispielen und Erfahrungen. Hier ist der vollständige Überblick:

  1. Null-Werte für Enumerationen
  2. Kein Mischen der Syntax
  3. Einrückungen und Umbrüche
  4. Mapping von Daten separieren
  5. Komplexe Lambda-Funktionen auslagern
  6. Behandlung von optionalen Filterkriterien
  7. Listen nicht von Hand befüllen
  8. Provider nicht mischen
  9. Die richtigen Methoden verwenden
  10. Methoden richtig verwenden
  11. Der Einsatz von “var”
  12. Anonyme Klassen
  13. Die Verwendung von Generics als Datentypen

Natürlich sind einige der Regeln relevanter, als andere. Und gelegentlich geht Lesbarkeit mit Kompromissen einher, etwa wenn die Verwendung eines Mappers (#4) oder vordefinierte Datentypen (#12) verhindern, dass eine komplexe Abfrage Daten aus mehreren Tabellen mit genau den benötigten Feldern zusammenführen kann.

In solchen Fällen ist Augenmaß gefragt. Guidelines sind Hilfen für die üblichen Fälle, sie haben keinen Anspruch auf Universalität und Unfehlbarkeit. Anders ausgedrückt: In Ausnahmefällen davon abzuweichen – und diese Ausnahme über einen Kommentar zu dokumentieren – ist völlig in Ordnung. Andererseits kann man solche Fälle aber auch als Denkanstoß nehmen und sich überlegen, ob eine komplexe Abfrage nicht besser in einer View oder Stored Procedure in die Datenbank aufgehoben wäre.

Damit schließe ich diese Serie ab. Falls jemand Anmerkungen (Widersprüche?) oder Ergänzungen hat, kann er mir die gerne mitteilen. Für eine gute Diskussion bin ich immer zu haben… ;-)

Share |

Exec SQL mit Parametern 19.06.2015

Alexander Kabisch
Alexander Kabisch, Principal eXpert
Dynamisches SQL wird gern verwendet, um komplexe Probleme schnell und einfach zu lösen. Sehr oft wird dieses SQL in Stored Procedures zusammengebaut, um beispielsweise Spalten situativ zu selektieren oder komplexe where-Statements zu erstellen.

Leider findet man oft SQL, das nicht typsicher und anfällig für Codeinjektion ist. Man stelle sich nur mal vor das @paramCODE mit 'ValueX’’; DROP TABLE ...--' gefüllt wäre.

   1: DECLARE @paramCODE AS VARCHAR(100) = 'ValueX';
   2:  
   3: DECLARE @sqlToExec AS VARCHAR(MAX) = 
   4:     'SELECT 
   5:         * 
   6:      FROM ... 
   7:      WHERE CODE = ''' + @paramCODE + ''''
   8: EXEC (@sqlToExec)

Oder wie konvertiert man am besten den Datentyp DATETIME nach VARCHAR?

   1: DECLARE @paramID AS INT = 20;
   2: DECLARE @paramStichtag AS DATETIME = '2014-01-01';
   3:  
   4: DECLARE @sqlToExec AS VARCHAR(MAX) = 
   5:     'SELECT 
   6:         * 
   7:      FROM ... 
   8:      WHERE ID = ' + STR(@paramID) + ' 
   9:      AND Stichtag = ''' + CONVERT(varchar,@paramStichtag,21) + ''''
  10: EXEC (@sqlToExec)

Wesentlich verbessert wird der Code durch den Einsatz von sp_executesql:

  • Übergabe der Parameter erfolgt ohne Konvertierung (Codeinjektion wird erschwert)
    • DROP Table wird nicht ausgeführt, sondern in der Suche (Where) benutzt
   1: DECLARE @paramCODE AS VARCHAR(100) = 'ValueX''; DROP TABLE ...--';
   2:  
   3: DECLARE @sqlToExec AS NVARCHAR(MAX) = 
   4:     'SELECT 
   5:         * 
   6:      FROM ...
   7:      WHERE CODE = @execParamCODE';
   8:  
   9: EXECUTE sp_executesql 
  10:         @sqlToExec, 
  11:         N'@execParamCODE VARCHAR(100)',
  12:             @execParamCODE = @paramCODE;
  • Übergabe der Parameter erfolgt typsicher
   1: DECLARE @paramID AS INT = 20;
   2: DECLARE @paramStichtag AS DATETIME = '2014-01-01';
   3:  
   4: DECLARE @sqlToExec AS NVARCHAR(MAX) = 
   5:     'SELECT 
   6:         * 
   7:      FROM ... 
   8:      WHERE ID = @execParamID
   9:      AND Stichtag = @execParamStichtag';
  10:  
  11: EXECUTE sp_executesql 
  12:         @sqlToExec, 
  13:         N'@execParamID INT, @execParamStichtag DATETIME',
  14:             @execParamID = @paramID, 
  15:             @execParamStichtag = @paramStichtag;

weitere Voreile:

  • Einsatz von OUTPUT Parametern ist möglich
  • Weniger ‘’’’’ und damit eine bessere Lesbarkeit
  • Kompilierung und mögliche Wiederverwendbarkeit* von Ausführungsplänen

Auch wenn der Aufruf von sp_executesql im ersten Moment komplexer wirkt, ist der Code am Ende für mich lesbarer, verständlicher und sicherer.

*) nur wenn @sqlToExec gleich ist, meist gibt es auch bei dynamischen SQL eine feste Anzahl von Möglichkeiten.

Share |

Xamarin.Android und die Android API Levels 16.06.2015

Stefan Gründig
Stefan Gründig, Chief eXpert

Bei der Konfiguration von Xamarin.Android-Projekten kann eingestellt werden, welche Android API Levels angewendet werden. So kann man festlegen, gegen welches Level kompiliert wird, welches Level auf dem Zielgerät mindestens vorausgesetzt wird und für welches Level die Anwendung eigentlich geschrieben wird. Dieser Artikel beleuchtet die Anwendung der Android API Levels im Kontext von Xamarin for Visual Studio. Da eine fehlerhafte Kombination von API Levels zum Crash der App führen kann, ist ein gutes Verständnis dafür sehr empfehlenswert.

Seitdem mit Xamarin bzw. Mono die Möglichkeit besteht, mit den Standard-Windows Entwicklerwerkzeugen (Visual Studio, C#) Anwendungen für Android zu erstellen, kommen auch .NET-Entwickler in den Genuss der Entwicklung von Android Apps. Um den Einstieg in die Thematik der Android API Levels zu erleichtern, beschreibt dieser Artikel den grundsätzlichen Umgang damit.

Ein API Level ist zunächst einmal nur eine Ganzzahl. Angefangen bei Level 1 ist zum Zeitpunkt der Entstehung dieses Artikels das aktuellste API Level 22. Jede neue Android-Version (aktuell v5.1 “Lollipop MR1”) bringt i. d. R. eine neue Revision der Android Framework API mit, welche durch das API Level gekennzeichnet wird. Die Framework API wird von Android Apps genutzt, um mit der Android Platform zu interagieren. Immer dann, wenn eine neue Android-Version Updates an der mitgelieferten API vornimmt, wird die Nummer des API Levels erhöht.

Updates an der Framework API sind abwärtskompatibel, so dass ältere Anwendungen weiterhin lauffähig bleiben. Updates sind additiv, d. h. wenn alte Bestandteile der API aktualisiert werden, so werden diese nicht entfernt, sondern nur als veraltet gekennzeichnet. Nur in wenigen Fällen, z. B. im Rahmen von Security Updates), kann es sein, dass API-Teile tatsächlich geändert oder sogar entfernt werden.

Jede Version der Android Platform unterstützt genau ein API Level, wobei aber immer frühere Levels implizit unterstützt werden. Die Android Developer Website enthält eine gute Übersicht über Android-Versionen und deren unterstütze API Levels.

Über die Verteilung der verschiedenen Android-Versionen und API Levels über den Android-Gerätemarkt liefern die Android Dashboards eine gute Übersicht. Gegenwärtig machen die Android-Versionen 4.1 bis 4.4 (JellyBean und Kitkat zu ähnlichen Anteilen) ca. 80% des Marktes aus (vgl. Android Dashboards). Lollipop (API Level 21 & 22) ist mit ca. 10% im Kommen. Damit sind die API Levels 16 bis 19 am stärksten im Markt vertreten, wobei 19 (Android 4.4 “Kitkat”) für sich genommen den Löwenanteil ausmacht. Wenn man also Apps für Android erstellt. Sollte man mindestens API Level 16 unterstützen, um den allergrößten Anteil der Geräte im Markt zu abzudecken.

Doch nun zum praktischen Teil.

Eingestellt werden die API Levels in einem Xamarin.Android App Visual Studio Project in den Projekteigenschaften im Bereich Application.

ProjectProperties

  • Bei "Compile using Android version" handelt es sich um das Target Framework, gegen das die App kompiliert wird.
  • "Minimum Android to target" meint die Minimum Android Version, also die kleinste Android-Version, die die App mindestens auf dem Zielgerät voraussetzt.
  • Die "Target Android Version" meint das API Level, für das die App primär programmiert wird.

Welche API Levels jeweils zur Auswahl stehen hängt davon ab, welche auf dem Entwicklungsrechner installiert sind. Die Installation erfolgt mit dem Android SDK Manager.

Die drei Einstellungen im Visual Studio Project werden im Folgenden näher erläutert.

Target Framework

Das Target Framework bezeichnet das API Level zur Entwicklungs-/Kompilierzeit und somit das API Level, gegen das die App vorweg geprüft und übersetzt wird. Das hier eingestellte Level bewirkt, dass die Anwendung zur Laufzeit davon ausgeht, dass dieses Level und dessen Funktionsumfang zur Verfügung stehen. Es sagt jedoch nichts darüber aus, welches Level zur Laufzeit tatsächlich verfügbar ist.

Aus dem eingestellten Target Framework ergeben sich die APIs, die zur Entwicklungszeit zur Verfügung stehen. Wird eine API-Funktion aufgerufen, die erst in einem höheren API Level als das eingestellte zur Verfügung steht, wird bereits vom Compiler ein Fehler gemeldet.

Target Android Version

Die Target Android Version bezeichnet das API Level, von dem die Anwendung ausgeht, dass es zur Laufzeit verfügbar ist. Dies ist somit die Android-Version, für die die App gedacht ist und primär entwickelt wird. Die App kann sich darauf verlassen, dass alle Funktionen dieser Version auf dem Zielgerät vollständig vorhanden sind und kann diese auch vollständig nutzen. Beim Deployment wird geprüft, ob die eingestellte Version auf dem Zielgerät vorhanden ist. Falls sie nicht vorhanden ist, wird sie beim Deployment bzw. der Installation aus dem Store mit eingeschlossen.

Normalerweise wird die Target Android Version dem Target Framework entsprechen. Es gibt allerdings Ausnahmen. So könnte eine verwendete Android Library eine höhere Target Android Version voraussetzen. In diesem Fall müsste für die App die Target Android Version höher eingestellt werden als das Target Framework.

Die Target Android Version signalisiert der Android Runtime, dass die App gegen dieses API Level erfolgreich getestet wurde. Das bedeutet für Android, dass keine besondere Kompatibilitätslogik ausgeführt werden muss, um die App auf einem Gerät mit diesem API Level auszuführen. Im anderen Fall, wenn das API Level auf dem Zielgerät höher ist als die Target Android Version der App, würde Android durch spezielles Verhalten für die Aufwärtskompatibilität der App sorgen.

Minimum Android Version

Dies ist die auf dem Zielgerät mindestens vorausgesetzte Android-Version. Wird diese niedriger eingestellt als das Target Framework, signalisiert dies die Abwärtskompatibilität der App.

Falls die App APIs aufruft, die in der Minimum Android Version noch nicht existieren, crasht die App zur Laufzeit. Es ist daher notwendig, dass im Code entsprechende Runtime Checks eingebaut werden, die eine bestimmte API nur dann aufrufen lassen, wenn diese auch vorhanden ist. Mono.Android enthält dafür entsprechende Hilfsklassen.

Runtime Checks

Setzt man die Minimum Android Version auf einen niedrigeren Wert als das Target Framework, könnten einige der im Code aufgerufenen APIs zur Laufzeit nicht verfügbar sein. Trotzdem könnte die App auf einem älteren Gerät laufen, dann allerdings ohne Verfügbarkeit bestimmter Features. Der Code der App muss in diesem Fall dafür Sorge tragen, dass nur die APIs aufgerufen werden, die auch verfügbar sind. Wie macht er das?

Die Assembly Mono.Android enthält dafür das abzufragende Property Android.OS.Build.Version.SdkInt, welches den BuildVersionCode zurückgibt. Ein konkreter Runtime Check, der z. B. prüft, ob mindestens Android 4.4 (Kitkat) vorliegt, sieht dann wie folgt aus:

   1: if (Android.OS.Build.Version.SdkInt >= Android.OS.BuildVersionCodes.Kitkat) 
   2: {
   3:
   4: }

Im Falle die erstellte App läuft in einer veralteten Umgebung, könnte die App z. B. den Benutzer informieren, dass ein bestimmtes Feature nicht zur Verfügung steht. Oder das bestimmte Feature wird stillschweigend nicht angeboten. Oder die App enthält eine Alternativimplementierung. Oder… Hier ist sicher die Kreativität des Entwicklers gefragt unter Berücksichtigung der User Experience. ;-)

API Level-Kombinationen

Bei der Wahl der API Levels sind Regeln zu beachten. So macht es beispielsweise keinen Sinn, gegen ein niedrigeres Target Framework zu kompilieren, als auf dem Zielgerät mindestens vorausgesetzt wird (Minimum Android Version). Oder auch gegen ein höheres Target Framework zu kompilieren, als Android durch die Target Android Version tatsächlich sicherstellt, ist nicht zulässig.

 

Target Framework (TF) =
Minimum Android Version (Min) = Target Android Version (TAV)

Normalfall.
Ein Xamarin.Android-Projekt enthält diese Kombination standardmäßig bei der Erstellung durch das Projekt-Template. Hier besteht keine Abwärtskompatibilität.

TF < Min

Nicht zulässig, da dies zu Inkompatibilität führt.

TF > Min

Abwärtskompatibilität der App, um ältere Android-Versionen zu unterstützen. Erfordert Runtime Checks im Code, um nicht unterstützte API-Aufrufe auf der jeweiligen Zielplattform zu verhindern.

TF < TAV

Empfohlen, wenn verwendete Bibliotheken ein höheres API Level voraussetzen (entspricht dem Target Framework der Bibliotheken).

TF > TAV

Nicht zulässig, da dies zu Inkompatibilität führt.

Min < TAV

Ist dann der Fall, wenn TF >= TAV ist und Abwärtskompatibilität entsprechend TF > Min gewährleistet werden soll.

Min > TAV

Nicht zulässig, da dies expliziter Aufwärtskompatibilität entsprechen würde und somit im Widerspruch zum umgesetzten Ansatz der Kompatibilitätssicherung stünde.

Bei unzulässigen Kombinationen warnt Visual Studio.

Warnungen

Android Libraries

Ein Xamarin.Android Class Library Project enthält im Gegensatz zu App Projects keine Möglichkeit zur expliziten Auswahl von Minimum und Target Android Version.

Library

Der Grund dafür ist, dass die Library in beliebigen Apps verwendet werden könnte, die für beliebige API Levels erstellt werden. Minimum und Target Android Version werden also von der App bestimmt, die die Library verwendet. Bei der Verwendung oder Erstellung von Android Libraries sollte demnach Folgendes beachtet werden.

  • Wenn eine Library konsumiert wird, sollte die Target Android Version mindestens so hoch sein, wie das Target Framework Level der Library. Das gilt im Übrigen auch für die Minimum Android Version, da man nicht wissen kann, dass die Library ein niedrigeres Level unterstützt als das, wogegen sie kompiliert worden ist.
  • Wenn eine Library erstellt wird, sollte deren Target Framework Level nicht höher als nötig eingestellt werden. Es ist gilt als Best Practice, dass man sich bei der Entwicklung einer Library auf die Verwendung möglichst weniger API Calls beschränkt, um die Library auf möglichst vielen API Levels schlussendlich verwenden zu können.

Fazit

Ein gutes Verständnis der Android API Levels ist notwendig. Es vermeidet Fehler, die erst zur Laufzeit auffallen und im schlimmsten Fall bis zum Endanwender durchschlagen sowie nur durch ein erneutes Deployment in den Store behoben werden können. Abschließend und zusammenfassend seien folgende Tipps gegeben.

  • Verwende für Target Framework, Target Android Version und Minimum Android Version standardmäßig das gleiche API Level. Weiche davon nur ab, wenn es gute Gründe dafür gibt, wie z. B. Abwärtskompatibilität zu gewährleisten.
  • Setze das Target Framework Level nur so hoch, wie für Deine App notwendig, wenn so viele Geräte wie möglich unterstützt werden sollen.
  • Beachte die Besonderheiten bei der Erstellung und dem Konsum von Android Libraries.

Siehe auch

Understanding Android API Levels (Xamarin Developer Portal)http://developer.xamarin.com/guides/android/application_fundamentals/understanding_android_api_levels

<uses-sdk> | Android Developers
http://developer.android.com/guide/topics/manifest/uses-sdk-element.html

Share |

LINQ Coding Guidelines #13–Verwendung von Generics als Datentypen 12.06.2015

Alexander Jung
Alexander Jung, Chief eXpert

Wenn es fertige Datentypen für die Abfrage gibt – zum Beispiel durch das Entity Framework generierte Klassen – liegt deren Verwendung auf der Hand. (Hat der letzte Beitrag nicht auch so angefangen? Egal…)
Bei trivialen Ausschnitten oder Sonderfällen sind aber oft grundlegende Datentypen aus dem .NET Framework oder eigene Generics eine Option.

Empfehlung:
* Beim Einsatz von Generics ist type inference zu unterstützen.
* Für Ergebnisdatentypen sollten dedizierte Datentypen verwendet werden. 

Gelegentlich hat man im Ergebnis mit Generics zu tun. Das kann am fachlichen Kontext liegen, wenn man Fachbibliotheken einsetzt (spontan fallen mir Matrizen als Beispiel ein). Oder man hat triviale Informationshäppchen aus zwei, drei Einzelwerten. Wie hier:

   1: public ApiExpert Get(int id)
   2: {
   3:     return this.db.eXperts
   4:         .Where(x => x.Id == id)
   5:         .ToArray()  
   6:         .Select(x => new ApiExpert
   7:         {
   8:             Id = x.Id,
   9:             IsAdmin = x.IsAdmin,
  10:             Name = x.Name,
  11:             CustomerResponse = x.CustomerStatements.Select(c =>
  12:                 new KeyValuePair<string, string>(c.Id.ToString(CultureInfo.InvariantCulture), c.Statement)
  13:                 )
  14:         })
  15:         .FirstOrDefault();
  16: }

In diesem Beispiel fällt sofort ein Grundproblem beim Einsatz von Generics auf: Bei Konstruktoren wird keine type inference unterstützt (auch wenn Eric Lippert das verteidigt soll sich das demnächst ändern). Ergebnis ist ein unleserliches Konstrukt.

Alternativer Ansatz sind Factory-Methoden, also statische Hilfsmethoden, die ein Objekt erzeugen – wobei type inference dann genutzt werden kann. Man kann sich diese selbst definieren, oder auf Datentypen ausweichen, die das schon mitbringen.

Dadurch wird der Ausdruck schon lesbarer:

   1: public ApiExpert Get(int id)
   2: {
   3:     return this.db.eXperts
   4:         .Where(x => x.Id == id)
   5:         .ToArray()  
   6:         .Select(x => new ApiExpert
   7:         {
   8:             Id = x.Id,
   9:             IsAdmin = x.IsAdmin,
  10:             Name = x.Name,
  11:             CustomerResponse = x.CustomerStatements.Select(c =>
  12:                 CreatePair(c.Id.ToString(CultureInfo.InvariantCulture), c.Statement)
  13:                 )
  14:         })
  15:         .FirstOrDefault();
  16: }

Noch lesbarer wird es, wenn man eine spezielle Extension Method bereitstellt, die auch die Intention deutlich macht:

   1: public ApiExpert Get(int id)
   2: {
   3:     return this.db.eXperts
   4:         .Where(x => x.Id == id)
   5:         .ToArray()  
   6:         .Select(x => new ApiExpert
   7:         {
   8:             Id = x.Id,
   9:             IsAdmin = x.IsAdmin,
  10:             Name = x.Name,
  11:             CustomerResponse = x.CustomerStatements.Select(c =>
  12:                 c.ToIdAndStatement()
  13:                 )
  14:         })
  15:         .FirstOrDefault();
  16: }

Damit haben wir die Abfrage ausreichend lesbar gestaltet.

Die Verwendung allgemeiner Datentypen sollte man aber ebenfalls im Auge behalten. KeyValuePair<> bietet die Properties Key und Value. Ob diese Benennung inhaltlich zur Bedeutung der  Daten passt ist eine andere Frage. Und Tuple<> macht sich mit Item1, Item2, etc. gleich ganz von jeder Bedeutung frei. Hier gilt eine ähnliche Empfehlung wie bei anonymen Datentypen: Die Definition eines dedizierten Datentyps ist – von einfachsten Fällen abgesehen – eine klare Empfehlung.

Share |

Los geht’s! DWX in Nürnberg 11.06.2015

Svenja Henß
Svenja Henß, Senior Assistant

Los gehts! Die SDX Xamarin Affen sind reisebereit.

Von Montag den 15. Juni bis Mittwoch den 17. Juni sind wir als
Bronze Sponsor auf der Developer Week in Nürnberg.

Besucht uns auf Stand 13, Ebene 2. Beweißt einen kühlen Kopf beim SDX Bilderrätsel und nimm einen Affen mit nach Hause. Oder du gewinnst mit ein bisschen Glück und es heißt für Dich "Ab-in-den-Urlaub". Smiley

WP_20150610_11_57_19_Pro

Share |