• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Android - Lessons Learned
 

Android - Lessons Learned

on

  • 811 views

Speaker: Lars Röwekamp auf der MobileTechCon 2012 in Frankfurt am Main ...

Speaker: Lars Röwekamp auf der MobileTechCon 2012 in Frankfurt am Main

Getreu dem Motto "Nichts ist wertvoller als Praxiserfahrungen. Aber was nützen sie, wenn man sie nicht teilt?" tauschen in dieser Session die Speaker ihre Real-Life-Projekterlebnisse mit den Teilnehmern aus. Dabei geht es nicht nur um Heldentaten, sondern vor allem auch um die vielen kleinen Stolperfallen, in die sie selbst schon einmal gelaufen sind. Die Teilnehmer erwartet eine Reihe wertvoller Tipps aus den Bereichen App-Architektur, App-Design und UI-Umsetzung, Nutzung der APIs, Kompatibilität und Hilfsbibliotheken, die es so eben nur in der Praxis gibt.

Statistics

Views

Total Views
811
Views on SlideShare
805
Embed Views
6

Actions

Likes
0
Downloads
0
Comments
0

1 Embed 6

http://www.openknowledge.de 6

Accessibility

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Android - Lessons Learned Android - Lessons Learned Presentation Transcript

    • Lars Röwekamp | CIO New Technologies@mobileLarson | @_openknowledge Android Dev Lessons Learned
    • Kunde drohnt mit Auftrag ...
    • „Can you do this?“
    • Can we do this?
    • „Can you do this?“
    • „Can you do this?“ „Yes, of course we can!“
    • „But, lots of pittfalls ahead.“ „And, lots of work to do.“
    • 35.000+ Produkte 2000+ Produktgruppen15.000+ Bilder 5.000+ Änderungen p.m.Komplexe Suche In-App NavigationInternational
    • Problem: Sehr, sehr viele Daten Lösung 1: ignorieren ...
    • App Size Limit: 50 MB (plus 2 x 2GB)
    • Problem: Sehr, sehr viele Daten. Lösung 2: DB Download ...
    • Problem: Sehr, sehr viele Daten. > DB Download > 200 MB+ > Wifi Check inkl. optional Loading > Inkrementeller Download inkl. Resume > einige Minuten > Vorab Hinweis auf „Ladezeit“ anzeigen > Working Progress Feedback inkl. „Step X of Y“ > Loading Progress Feedback inkl. „X von Y“
    • Problem: Sehr, sehr viele Daten. > DB Download > Check for WiFi <!-- WiFi check: Declare Wifi as needed --> <manifest ...>     <uses-feature android:name="android.hardware.wifi" android:required=["true"|"false"] />     ... </manifest>
    • Problem: Sehr, sehr viele Daten. > DB Download > Check for WiFi only // WiFi check: check for existing WiFi ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); " State wifi = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI) "" " " .getState(); if (wifi == NetworkInfo.State.CONNECTED || wifi == NetworkInfo.State.CONNECTING) { // WiFi is available " } else { ...
    • Problem: Sehr, sehr viele Daten. > DB Download > Check for WiFi Details // WiFi check: check for WiFi detail info WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); WifiInfo wifiInfo = wifiManager.getConnectionInfo(); SupplicantState wifiState = wifiInfo.getSupplicantState(); if (wifiState == SupplicantState.COMPLETED) { // WiFi is available - get some wifiInfo details ... " } else { ...
    • Problem: Sehr, sehr viele Daten. > DB Download > Check for WiFi Details // WiFi check: check for WiFi detail info WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); WifiInfo wifiInfo = wifiManager.getConnectionInfo(); SupplicantState wifiState = wifiInfo.getSupplicantState(); if (wifiState == SupplicantState.COMPLETED) { // WiFi is available - get some wifiInfo details ... " } else { ...
    • Problem: Sehr, sehr viele Daten. > DB Download > Incremental Loading // Prepare download with DownloadManager 1/2 DownloadManager.Request downloadRequest = new DownloadManager.Request(Uri.parse(DOWNLOAD_URI)); // set additional optional information: // Title, Description, MimeType, ExternalFileDir, ... // allow download via Mobile or Wifi downloadRequest.setAllowedNetworkTypes( DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE); // do not show the file in "Downloads" downloadRequest.setVisibleInDownloadsUi(false);
    • Problem: Sehr, sehr viele Daten. > DB Download > Incremental Loading // Start download with DownloadManager 2/2 ... // register broadcast receiver for DOWNLOAD_COMPLETE IntentFilter intentFilter = new IntentFilter( DownloadManager.ACTION_DOWNLOAD_COMPLETE); registerReceiver(broadcastReceiver, intentFilter); // Enqueue download downloadId = downloadManager.enqueue(downloadRequest);
    • Problem: Sehr, sehr viele Daten. > DB Download > Showing Progress // Loading progress - base version public class ProgressActivity extends Activity { " private ProgressBar mProgress; // or ProgressDialog private int mProgressStatus = 0; private Handler mHandler = new Handler(); protected void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.progressbar_activity); mProgress = (ProgressBar)findViewById(R.id.pb); // Start some work in background thread doWorkInBackground(); } ... }
    • Problem: Sehr, sehr viele Daten. > DB Download > Showing Progress " // doWorkInBackground() implementation new Thread(new Runnable() { " public void run() { " while (mProgressStatus < 100) { " mProgressStatus = doSomeWork(); " // Update progress bar in UI thread ! mHandler.post(new Runnable() { ! public void run() {! mProgress.setProgress(mProgressStatus); ! } ! }); " } } }).start();
    • Problem: Sehr, sehr viele Daten. > DB Download > Showing Progress <!-- Spinning wheel -->   <ProgressBar      style="@android:style/Widget.ProgressBar.Large"      ... /> <!-- Progress bar from 0 .. 100 -->   <ProgressBar      style="@android:style/Widget.ProgressBar.Horizontal"      ... />
    • Problem: Sehr, sehr viele Daten. Lösung 2: DB Download+ ...
    • Problem: Sehr, sehr viele Daten. > DB Download+ > ca. 10 MB > Lazy Loading Ansatz zum Füllen der DB > Nur Basisdaten initial laden/vorhalten > Produktdetails und Bilder „as needed“ > Unterstützte Funktionen > Home Page Angebote anzeigen > Kategorien anzeigen > Suchen1), Filtern, ...
    • Problem: Sehr, sehr viele Daten. > DB Download+ 1) Online-/Offline-Suche > ca. 10 MB > Lazy Loading Ansatz zum Füllen der DB > Nur Basisdaten initial laden/vorhalten > Produktdetails und Bilder „as needed“ > Unterstützte Funktionen > Home Page Angebote anzeigen > Kategorien anzeigen > Suchen1), Filtern, ...
    • Problem: Sehr, sehr viele Daten. > DB Download+
    • Problem: Sehr, sehr viele Daten. > DB Download+
    • Problem: Viele Änderungen. Lösung 1: Update Protokoll
    • Problem: Viele Änderungen. > Update Protokoll > ca. 5000 Änderungen p.M. > Modification Info zum „Start-up“ laden > Neue/geänderte/gelöschte Produkte/Bilder > Protokoll > Gelöschte Produkte/Bilder löschen > Neue Produkte/Bilder laden > Geänderte Produkte/Bilder laden
    • Problem: Viele Änderungen. Lösung 2: Update Protokoll+
    • Problem: Viele Änderungen. > Update Protokoll+ > ca. 5000 Änderungen p.M. > Modification Info zum „Start-up“ laden > Produktdetails „as needed“ > Protokoll > Neue Produkte als Dummy anlegen > Gelöschte Produkte markieren > Geänderte Produkte markieren > Aufräumen „on-the-fly“
    • Problem: Viele Änderungen. > Update Protokoll+ > ca. 5000 Änderungen p.M. > Modification Info zum „Start-up“ laden > Produktdetails „as needed“ > Protokoll > Neue Produkte als Dummy anlegen > Gelöschte Produkte markieren > Geänderte Produkte markieren > Aufräumen „on-the-fly“
    • Problem: Lesbare Datenbank. Lösung: Encryption ...
    • Problem: Lesbare Datenbank. > Encryption > DB im Android Filesystem > DB Verschlüsselung via SQLCipher > 256-bit AES Encryption für SQLite > Proxies für wichtigsten Android DB Klassen > SQLCipher anwenden > Step 1: Imports setzen > Step 2: SQLCipher Libs laden > Step 3: alles wie sonst auch
    • Problem: Lesbare Datenbank. > Encryption // Step 1: import sqlcipher import info.guardianproject.database. sqlcipher.SQLDatabase; // Trigger database initialization public class SqlCypherActivity extends Activity { ... }
    • Problem: Lesbare Datenbank. > Encryption // Trigger database initialization public class SqlCypherActivity extends Activity { " @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); initializeSQLCipher(); } ... }
    • Problem: Lesbare Datenbank. > Encryption // Trigger database initialization public class SqlCypherActivity extends Activity { private void InitializeSQLCipher() { // Step 2: Load SQLCipher Libs SQLiteDatabase.loadLibs(this); // Step 3: Business as usal ... } ... }
    • Problem: Lesbare Datenbank. > Encryption Achtung: ICS Bug! // Trigger database initialization public class SqlCypherActivity extends Activity { private void InitializeSQLCipher() { // Step 2: Load SQLCipher Libs SQLiteDatabase.loadLibs(this); // Step 3: Business as usal ... } ... }
    • Problem: Ärger zur Laufzeit. Lösung 1: gibt‘s nicht ...
    • Problem: Ärger zur Laufzeit. > Gibt‘s nicht, gibt es nicht!
    • Problem: Ärger zur Laufzeit. Lösung 2: ... leider doch!
    • Problem: Ärger zur Laufzeit. > Gibt‘s leider doch > Tracking - easy version > Android App Error Reports (seit Vers. 2.2) > User triggert Crash & Freeze Report > Tracking - eXtended Version > Application Crash Report for Android (ACRA) > Konfigurierbare Report Varianten/Ziele > Erweiterbar um „Bug-Digger“ wie bugsense
    • Problem: Ärger zur Laufzeit. > Gibt‘s leider doch > Crash Report Report >>
    • Problem: Ärger zur Laufzeit. > Gibt‘s leider doch > ACRA > Inidviduelle CrashReport Ziele > Google Docs, eMail, HTTP-Post Script > beliebige Ziele mittels eigenem Sender > Individuelle CrashReport User Interaktion > Silent Mode, Toast, Notifcation > Individuelle CrashReport Daten > Device Info, Custom Data, LogCat, ...
    • Problem: Ärger zur Laufzeit. > Gibt‘s leider doch > ACRA
    • Problem: Ärger zur Laufzeit. > Gibt‘s leider doch > ACRA // ACRA setup and initialization for Google Docs import org.acra.*; import org.acra.annotation.*; @ReportsCrashes(formKey = "...") public class MyApplication extends Application { ... @Override     public void onCreate() {         ACRA.init(this);         super.onCreate();     } ... }
    • Problem: Ärger zur Laufzeit. > Gibt‘s leider doch > ACRA // ACRA setup and initialization for own target @ReportsCrashes(formURI="http://...", formKey="") public class MyApplication extends Application { ... @Override     public void onCreate() {       ACRA.init(this); MySender mySender = new MySender(what,params,needed);    ErrorReporter.getInstance().setReportSender(mySender);       super.onCreate();     } ... }
    • Problem: Ärger zur Laufzeit. > Gibt‘s leider doch > ACRA // ACRA setup and initialization for special data @ReportsCrashes(formKey = "...",       customReportContent = { APP_VERSION, ANDROID_VERSION, PHONE_MODEL, CUSTOM_DATA, STACK_TRACE, LOGCAT },                         mode = ReportingInteractionMode.TOAST,          resToastText = R.string.crash_toast_text) public class MyApplication extends Application { ... }
    • Problem: Ärger zur Laufzeit. > Gibt‘s leider doch > bugsense
    • Problem: Ärger zur Laufzeit. > Gibt‘s leider doch > bugsense
    • Problem: Diversifikation Lösung 1: Ignorieren
    • Problem: Diversifikation 1.5 4,2 % 1.6 16,7 % 2.1 15,5 % 2.2 2.3.x 3.1 3.2 4+ 60,6 %
    • Problem: Diversifikation Lösung 2: Teilweise ignorieren
    • Problem: Diversifikation 1.5 4,2 % 1.6 16,7 % 2.1 15,5 % 2.2 2.3.x 3.1 3.2 4+ 60,6 %
    • Problem: Diversifikation 1.5 4,2 % 1.6 16,7 % 2.1 15,5 % 2.2 2.3.x 3.1 3.2 4+ 60,6 %
    • Problem: Diversifikation 1.5 4,2 % 1.6 16,7 % 2.1 15,5 % 2.2 2.3.x 3.1 3.2 4+ 60,6 %
    • Problem: Diversifikation > Unified UI
    • Problem: Diversifikation > Unified UI
    • Problem: Komplexe Suche Lösung: Server-Side Search
    • Problem: Komplexe Suche > Server-Side Search > Warum? > Komplexe Suchalgorithmen > Komplexe Produktzusammenhänge > Darum! > Einfache Suche „on device“ > Erweiterte Suche parallel „on server“ > Dynamischen Aufbauen der Ergebnisse
    • Problem: In-App Navigation Lösung: In-App Navigation ;-)
    • Problem: In-App Navigation > In-App Navigation > Back vs. Up > „Back“ berücksichtigt Activity Stack > „Up“ berücksichtigt Use Case Stack > In-App Navigation > Up-Navigation via In-App Buttons > Manipulation des Activity Stacks > Für Home und „Main Activities“
    • Problem: International Lösung: Ressource Mgmt.
    • Problem: International > In-App Navigation > Ressouce Management - easy Version > Texte, Bilder, Icons > Datum, Währung > Schriftsatz (Unicode) > Ressouce Management - eXtended Version > Server-side Data > Sprache vs. Land > Algorithmen
    • Demo