![]() ![]() Hallo! Du bist nicht angemeldet. Wenn Du Dich anmeldest, dann kannst Du hier Kommentare verfassen und Dich mit anderen Nutzern austauschen. Es werden keine Daten von Dir ausspioniert und nach einer Stunde wirst Du hier automatisch wieder abgemeldet. Jetzt für den Kammerath Network Newsletter anmelden und mit einem bisschen Glück einen 20,- € Amazon-Gutschein gewinnen! Internet (43) Technik (41) Linux (18) Programmierung (17) OpenWrt (6) Sonstiges (6) WLAN (6) Web Analytics (5) Asterisk (3) Raspberry Pi (2) Weiterempfehlen « Android App programmieren » (29.10.2011 21:00)
Wobei meine größte Motivation mit Sicherheit nicht finanzieller Natur ist, sondern ich gerne Menschen Informationen vermittle. Nun wollte ich eben eine Android App programmieren, mit welcher man sehen kann, wieviele Bestellungen man erzeugt hat und wieviel Provision dadurch entstanden ist. Ich finde, dass das auch eine interessante Idee ist, mit der man mal schnell eine Android App programmieren kann. Bevor ich aber zu sehr ins Detail einsteige, was ich defintiv weiter unten noch tun werde, möchte ich einmal ganz von Vorne anfangen. Was man für das Programmieren einer Android App braucht
So grundlegende Dinge wie Internetzugang oder ein Android Gerät, auf dem man das dann mal wirklich testen kann, nehme ich jetzt nicht mit auf. Beim Android App Programmieren braucht man auch kein extremes Supergerät, es reichen auch einfache und günstige Android-Geräte als Testgeräte aus.
Nachdem wir den SDK installiert haben, starten wir Eclipse und wählen dort den Menüpunkt "Help" und dann "Install New Software" aus. Rechts oben klickt man dann auf Add und fügt die URL hinzu: https://dl-ssl.google.com/android/eclipse/. Danach wählt man die Software und klickt entsprechend immer weiter auf Next. Wer dazu eine sehr detaillierte Anleitung braucht, findet diese in der Android Developer Dokumentation unter "ADT Plugin for Eclipse". Die erste Android App programmieren
Damit man nun diese kleine Miniatur App auch starten kann, muss man zunächst eine Laufzeitkonfiguration anlegen. Dazu geht man unter Eclipse zu "Run" und dann "Run Configurations". Dort legt man mit Rechtsklick auf "Android Application" mit "New" eine neue Konfiguration an, wählt das Projekt aus und als "Target" das mit dem VDM erstellte Gerät. Sollte dies dort noch nicht auftauchen, hilft ein kurzer Neustart von Eclipse. Ich musste nach der SDK Installation auch erstmal das System neustarten. Danach kann man über "Run" die App entsprechend auf dem Emulator-Gerät starten.
Der Emulator bringt alle Features mit, die auch ein Android Gerät mitbringt. So hat dieser auch den Browser, Maps, Mail und alle Einstellungen an Bord. Wer also neben Apps z.B. auch mobile Websites programmieren möchte, der kann den Emulator natürlich auch für das Testen eben solcher Websites benutzen. Bei der App Entwicklung unterstützt er auch Debugging, was aber in der Ausführungszeit bedeutend langsamer ist als normales Ausführen und ich hatte ab und an schonmal ein paar Aussetzer mit dem Ding. Eintauchen in die Android App ProgrammierungWollen wir nach der kurzen Aufwärmrunde also nun etwas konkreter werden. Bevor wir jetzt jedoch vollständig im Code versinken, möchte ich die Gelegenheit nutzen und Einsteigern in die Programmierung noch das Buch "Java ist auch eine Insel" ans Herz legen. Es steht bei Galileo Open auch kostenfrei online zur Verfügung: http://openbook.galileocomputing.de/javainsel/. Für eine gute Programmierung ist es unerlässlig, dass man genau weiß, was man wann und wo tut. Grundsolide Java-Kenntnisse sind ein absolutes Muss, wenn man mit der Android App Programmierung anfängt. Wer bereits Vorkenntnisse in C# oder C++ hat, dem brauche ich hier wohl nicht mehr viel erzählen. Eine Spezifikation zur Programmierung der Android AppDas Schreiben einer Spezifikation klingt immer so nach fieser Bürokratie. Es ist aber enorm wichtig, dass man einen Plan hat, wie man zu seinem Endergebnis kommt. Man sollte sich daher entweder den Ablauf skizzieren oder entsprechend die Funktionen beschreiben. Für eine kleine nette App muss man jetzt auch nicht direkt zu UML für die Modellierung greifen. Es reicht für den Anfang ein Stück Papier - wir wollen es ja nicht übertreiben. Die ersten Zeilen der Android AppWenn man nach der obigen Beschreibung ein neues Android Projekt erstellt hat, dann trifft man zunächst auf eine Klasse, die von einer Basis-Klasse namens "Activity" abgeleitet ist. Für eine "Hello World" Beispielanwendung erstellt Eclipse als Android Projekt standardmäßig etwas wie den folgenden Code. public class HelloWorld extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
Dieser einfache Code erklärt sich fast von selbst. Zum einen wird der Basiskonstruktor aufgerufen und zum anderen mit "setContentView" mitgeteilt, dass das View Layout mit dem Namen "main" verwendet werden soll. Android bringt hier auch direkt einen hervorragenden GUI Designer mit. Unter "/src/res/layout/main.xml" findet man die Datei. Mit einem Doppelklick darauf sollte der folgende GUI Designer hervor kommen. Sollte dem nicht der Fall sein, dann einfach mit Rechtsklick "Open With" und dann "Android Layout Editor" auswählen. Ich hatte ein paar Mal Probleme, dass Eclipse das nur als XML Datei mit dem Standardeditor geöffnet hat.
Einen Login Dialog in der Android App anzeigenDa meine App sich ja mit meinen Benutzerdaten bei Amazon anmelden muss, muss sie entsprechend beim Start vom Benutzer den Benutzernamen und das Passwort erfragen. Dazu habe ich mir überlegt, dass ich einen Dialog anzeige, welcher nach Benutzername und Passwort fragt und nicht wie häufig üblich eine völlig neue View im Vollbildmodus anzeige. Modale Dialoge haben den Vorteil, dass der Anwender im Hintergrund bereits erkennen kann, was Ihn erwartet.
final View loginDialogView = factory.inflate(R.layout.logindialog, null);
final EditText usernameInput = (EditText)
loginDialogView.findViewById(R.id.UsernameEditText);
final EditText passwordInput = (EditText)
loginDialogView.findViewById(R.id.PasswordEditText);
final CheckBox StoreCredentialsLocallyCheckBox
= (CheckBox)loginDialogView.findViewById
(R.id.StoreCredentialsLocallyCheckBox);
AlertDialog loginDialog = new AlertDialog.Builder(AmazonPartnerNetActivity.this)
.setTitle("Amazon PartnerNet Login")
.setView(loginDialogView)
.setPositiveButton("Login", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// onclick code for further execution
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
AmazonPartnerNetActivity.this.finish();
}
})
.create();
loginDialog.show();
Solche Buttons sind für den Anwender gewohnter und werden in zukünftigen Android Versionen sich besser an neue Layouts anpassen. Beim Negativ-Button terminiert sich unsere Android Activity - also das Programm wird umgehend beendet und beim Positiv-Button habe ich den Code entfernt, weil der Block so groß war. Dort geht es einfach mit der Applikation weiter. Zum Schluss dann noch der Aufruf der Show-Methode und der Dialog erscheint in voller Pracht. Standard-Dialoge in der Android App anzeigenMit dem Login Dialog hat man auch schon so gut wie die ganze Komplexität der Android Dialogmöglichkeiten abgefrühstückt. Die Anroid Dokumentation zu Dialogen führt den Login Dialog als Letztes und kompliziertestes auf, da es sich hierbei um einen individuellen Dialog handelt (Custom Dialog). Im nächsten Abschnitt zum Thema Multi-Tasking verwende ich z.B. noch einen sog. ProgressDialog, also einen Fortschrittsdialog. Dieser lässt sich mit einer Zeile Code sehr einfach erzeugen. ProgressDialog progressDialog = ProgressDialog.show(AmazonPartnerNetActivity.this,
"Amazon PartnerNet", "Logging in & fetching data", true);
Der Klassiker unter den Dialogen ist natürlich die unter JavaScript bekannte AlertBox und bei .NET als MessageBox bezeichnete Box, die einen einfachen Meldedialog mit Text und Ein, Zwei oder Drei Buttons darstellt. Einen solchen Dialog kann man auch unter Android relativ schnell und einfach erstellen. final AmazonPartnerNetActivity tActivity = this;
// display an error message
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Error fetching data: Server did not return expected data")
.setCancelable(false)
.setTitle("Data retrieval failed")
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// cancel the thread first so that
// the user can retry logging in
tActivity.client.cancel(true);
// show the login dialog once more
tActivity.showLoginDialog();
}
});
AlertDialog alert = builder.create();
alert.show();
Bei diesem Beispiel erscheint ein Android Standarddialog mit einem OK Button, einer Überschrift und einem Fehlertext, dass die Daten nicht verarbeitet werden konnten. Man sollte sich nur mit Dialogen zurück halten, denn zu viele Dialoge hintereinander nerven den Benutzer auch. Das ist bei Entwicklern ein häufiger Fehler. Man sollte sich bei einer guten Mischung aus Dialogen und direkten Fehlern auf Eingabemasken halten. Multi-Threading Android App ProgrammierungMittlerweile wird auch bei Android Geräten dazu übergegangen Dual Core Prozessoren einzusetzen. Das hat für Entwickler und für den Anwender großartige Vorteile, da man nicht nur mehr Rechenleistung hat, sondern auch sehr gut parallelisieren kann. Als Entwickler ist man aber gefordert, hier auch dafür zu sorgen, dass das Betriebsystem - also Android selbst - die Last möglichst gut auf beide Prozessorkerne verteilen kann. Werfen wir dazu zunächst einmal einen Blick auf den Aufbau des ARM Cortex-A9 MPCore Multi Core Prozessors. Die Cortex A9 Architektur befindet sich u.A. in den OMAP4 Prozessoren von Texas Instruments, welche z.B. im Motorola Droid Razr oder im Samsung Galaxy Nexus verbaut sind.
Werden wir einmal konkret: Meine App braucht bei guter Netzabdeckung 10 bis 20 Sekunden dafür, die Daten von Amazon zu laden. Währenddessen würde bei einem einzigen Thread die komplette Ausführung der Anwendung durch das Herunterladen blockiert. Die Benutzeroberfläche würde nicht mehr auf Eingaben reagieren und "einfrieren". Damit ich nun z.B. einen Fortschrittsbalken anzeigen kann, muss ich dieses "Einfrieren" verhindern. Das geht dadurch, dass das Herunterladen in einem anderen Thread läuft als die grafische Oberfläche mit dem "Hauptprogramm". Software-seitig ist das auch gleich bedeutend einfacher als es sich in der Hardware-Ebene anhört. Android bringt direkt eine Klasse für das Multi-Threading mit dem Namen AsyncTask mit. Herimit hat man bereits alle notwenidgen Grundlagen, um sofort und einfach mit dem Multi-Threading zu beginnen und dem Betriebssystem, der JVM und der SCU alle notwendigen Grundlagen zu geben, um beide Prozessorkerne mit maximaler Effizienz zu betreiben. public class amznclient extends AsyncTask {
/* ... Code removed to reduce the size of this sample ... */
@Override
protected String doInBackground(String... params) {
String result;
try {
result = this.fetch();
} catch (Exception e) {
Log.e("AppName", e.getMessage());
result = null;
}
return result;
}
@Override
protected void onPostExecute(String result) {
// notify the parent thread that we're finished here
this.parentActivity.updateDataReady(result);
}
}
Im Beispielcode sehen wir jetzt eine Klasse, die von AsyncTask abgeleitet ist und die Methoden onPostExecute sowie doInBackground implementiert. Letztere wird dann ausgeführt, wenn Jemand die "execute()" Methode aufruft, die durch AsyncTask vererbt wurde. Sobald der Thread dann durch ist, führt AsyncTask die Methode onPostExecute aus, mit welcher man dann dem ursprünglichen Thread die Information übergeben kann, dass der erstellte Thread nun fertig ist. Konkret: Die Oberfläche startet den Thread "amznclient", welcher den Login durchführt und die Berichtsdaten abfragt, während die grafische Oberfläche während der gesamten Thread-Laufzeit einen ProgressDialog anzeigt. Daten von einem Webserver mit der Android App abrufenSei es meine App, Facebook, Google Mail, ein Shop, ein Preisvergleich oder eine Fluggesellschaft - das Prozedre der meistens Apps ist gleich: Sie fragen Daten auf einem entfernten Server an und bereiten diese grafisch in der App auf. Bei Facebook kann man gleich noch seine eigenen Daten an den Server übertragen. Wer solch eine App entwickelt, wird häufig dazu passend auch auf einem Webserver eine Anwendung entwickeln, die eine entsprechende XML, JSON oder SOAP Schnittstelle bereitstellt. Da ich in meiner App die Daten von Amazon als XML bekomme, habe ich den Apache HttpClient benutzt, den man definitiv der HttpURLConnection vorziehen sollte. HttpGet getMethod = new HttpGet(url);
getMethod.setHeader("User-Agent", userAgent);
this.localContext.setAttribute(ClientContext.COOKIE_STORE, this.cookieStore);
this.httpClient.setCookieStore(this.cookieStore);
response = this.httpClient.execute(getMethod,this.localContext);
locationHeader = getMethod.getFirstHeader("Location");
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) {
data = responseHandler.handleResponse(response);
}
Mit diesem Teil habe ich definitiv die meiste Zeit verbracht. Grund hierfür war, dass nirgendwo dokumentiert ist, dass der HttpClient den HttpContext und den CookieStore neu zugewiesen bekommen muss, wenn man eine neue Methode erstellt. Das und die Tatsache, dass ich Anfangs die unbrauchbare HttpUrlConnection verwendet habe, hat den allergrößten Batzen geschluckt. Die vollständige Klasse mit HTTP POST Methode findet man in der Versionkontrolle als amznclient.java. Da Amazon für den Login keine API anbietet, ist die Klasse auch direkt ein Screen Scraper. Damit die App auch noch die Berechtigung bekommt auf das Internet zuzugreifen, muss man in der AndroidManifest.xml Datei noch einen android.permission.INTERNET Knoten hinzufügen. Wie das genau aussieht kann man in der AndroidManifest.xml Datei von meiner App sehen.
Verarbeitung von XML Daten in Android Apps mit dem DOMWie eingangs bereits erwähnt lädt meine Beispiel-App die Daten von Amazon im XML Format herunter, was nun natürlich bedeutet, dass eben jene Daten auch mit einem Parser ausgewertet werden müssen. Dazu kann man ganz einfach und Schnell den Android DOM Parser nehmen. Ich benutze ihn auch auf anderen Plattformen sehr gerne und fand die Umsetzung auch kinderleicht. DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new ByteArrayInputStream(XmlData.getBytes()));
TextView ShipmentTotalUnitsTextView = (TextView)this.findViewById
(R.id.ShipmentTotalUnitsTextView);
NodeList shipmentTotalXml = doc.getElementsByTagName("ShipmentTotals");
NodeList shipmentTotalList = shipmentTotalXml.item(0).getChildNodes();
for(int n=0; n shipmentTotalList.getLength(); n++){
if(shipmentTotalList.item(n).getNodeName().equals("Units")){
String shippedUnitsValue = shipmentTotalList.item(n)
.getChildNodes().item(0).getNodeValue();
ShipmentTotalUnitsTextView.setText(shippedUnitsValue);
}
}
Der kurze und knappe Code zeigt einfach einmal, wie man einzelne Knoten aus einem XML String ausliest. Die dazugehörige XML Datei hat im Prinzip einfach drei Ebenen. Einen Root-Knoten, dann einen ShopmentTotals Knoten und zum Schluss einne Units-Knoten, der dann als Wert entsprechend die versendeten Einheiten hat. Schlussendlich wird der Wert dann in ein TextView geschrieben. Mehr gibt es zu XML unter Android auch nicht mehr zu sagen. Einstellungen und Benutzerdaten für die Android App speichernFür das Speichern von Benutzereinstellungen, persönlichen Daten und anderen Dingen bietet Android direkt eine Klasse namens "SharedPreferences", welche auf Schlüsselbasis Daten für eine Anwendung speichern kann. Das ganze ist so einfach, dass man mit folgendem Zweizeiler schon Daten gespeichert hat. // MODE_PRIVATE defines that
// no other app can access the data
SharedPreferences settings = this.getSharedPreferences
("MyAppNamePrefs", MODE_PRIVATE);
// save data in the shared preferences
SharedPreferences.Editor editor = settings.edit();
editor.putString("Username", "Hans Wurst");
editor.putBoolean("IsMaleUser", true);
editor.commit();
// remove the setting again
editor.remove("Username");
editor.commit();
Dazu kann man dann auch nicht mehr allzu viel sagen außer: Speichern, Auslesen, Bearbeiten, Löschen, Fertig. Mehr gibt es damit auch nicht zu tun. Ich finde das super positiv, da man nicht mehr aufwendig Konfiugrationsdateien speichern muss, wie unter Windows. Ansonsten gibt es wohl noch SQLite Treiber für Leute, die keine Luste auf sowas haben oder eine Datenbank brauchen. Android App auf einem Gerät installieren |