SlideShare ist ein Scribd-Unternehmen logo
1 von 80
Downloaden Sie, um offline zu lesen
FSIV10 THORSTEN WEISKOPF 
APPLIKATIONSENTWICKLUNG FÜR ANDROID
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
2 
1 Einführung ................................................................................................... 3 
2 Kapitel 1 – Android Grundlagen ................................................................... 4 
2.1 Was ist Android? ........................................................................................................... 4 
2.2 Die Entwicklungsumgebung .......................................................................................... 4 
2.3 Google ADT.................................................................................................................... 5 
2.4 Grober Aufbau einer Android App ................................................................................ 8 
2.5 Grundlagen der Android Entwicklung ......................................................................... 10 
2.5.1 View-Activity-Event-Intent .................................................................................. 10 
2.5.2 Activity Lebenszyklus........................................................................................... 12 
2.5.3 Die wichtigsten XML Dateien ausserhalb der Layouts ........................................ 14 
2.5.4 Persistenz und Datenspeicherung in Adnroid ..................................................... 15 
3 Kapitel 2 - App Dokumentation LittleProjectManager ................................ 16 
3.1 Beschreibung der Applikation ..................................................................................... 16 
3.2 Architektur und Funktionsweise der Applikation ....................................................... 18 
3.2.1 Activity-View und Layout (VIEW) ........................................................................ 18 
3.2.2 Activitys (Controller) ........................................................................................... 20 
3.2.3 Dialogfragmente (Controller) .............................................................................. 23 
3.2.4 Plain-Old-Java-Objects (Model) .......................................................................... 24 
3.2.5 DataAccessObjects (Model) ................................................................................ 24 
3.2.6 MySQLiteHelper und seine Tabellenklassen (Model) ......................................... 25 
3.3 SQLite Datenbank ........................................................................................................ 26 
3.3.1 Datenbankstruktur .............................................................................................. 27 
3.4 Projekt und Paketstruktur ........................................................................................... 29 
3.4.1 Pakete und Klassen ............................................................................................. 29 
3.4.2 Projektdateien und Ressourcen .......................................................................... 31 
4 Ausblick und Fazit ..................................................................................... 33 
5 Abbildungsverzeichnis ............................................................................... 34 
6 Abkürzungsverzeichnis .............................................................................. 35 
7 Anlagen ..................................................................................................... 36 
7.1 Eclipse Workbench ...................................................................................................... 37 
7.2 Screenshots LittleProjectManager .............................................................................. 38 
7.3 Architekturschaubild ................................................................................................... 40 
7.4 Quellcode der Applikation .......................................................................................... 41
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
3 
1 Einführung 
Dieses Dokument entstand im Rahmen einer abschließenden Leistungsfeststellung des Modules Softwareentwicklung. Vorgabe war es das Gebiet der Android Applikationsentwicklung zu erschließen und eine für den Bereich typische Applikation zu realisieren. Das Dokument gliedert sich daher auch in zwei Bereiche. Kapitel eins beschreibt die Grundlagen der Applikationsentwicklung, während Kapitel zwei die Architektur und Funktionsweise der, im Rahmen der ALF erstellten, Applikation „LittleProjektManager“ beschreibt. Im Anhang finden sich unter anderem Screenshots der Applikation, Diagramme und der gesamte Quellcode der Applikation.
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
4 
2 Kapitel 1 – Android Grundlagen 
2.1 Was ist Android? 
Android ist ein hauptsächlich von Google getriebenes „Open Source Projekt“ und wurde ursprünglich als Betriebssystem für mobile Geräte entwickelt. Es findet jedoch mittlerweile auch auf anderen Geräten wie Fernsehern Anwendung. Nach meiner persönlichen Einschätzung wird es nicht lange dabei bleiben. Es gibt bereits Modelle für Uhren, Spielekonsolen und „intelligente Haushaltsgeräte“ wie Kühlschränke und Spiegel auf denen Android läuft. 
Im Kern besteht das Betriebssystem aus einem Linux Kernel welcher den Hardwarezugriff und die Speicherverwaltung regelt. Gleich darauf aufgesetzt läuft eine auf Java Technologie basierende virtuelle Maschine mit einer entsprechenden Android Klassenbibliothek. Die virtuelle Maschine führt dann den Bytecode bestimmter Module oder der programmierten Android Applikation aus. Um jetzt Applikationen, also Anwendungen oder Apps, zu entwickeln stellt Google ein „Java Programming Interface“ mit einer Reihe von Tools zur Verfügung. 
Zusätzlich können auch bereits vorhandene Softwarekomponenten mit verwendet werden. Zum Beispiel die Tastatur, die Medienwiedergabe, der Browser, die SQLite Datenbank oder OpenGL für 3D Grafik, um nur mal einen Auszug zu nennen. 
2.2 Die Entwicklungsumgebung 
Im Prinzip könnten die Apps in einem einfachen Editor geschrieben werden und per Android Service Development Kid zu Bytecode kompiliert, um anschließend in der virtuellen Maschine des Android Gerätes ausgeführt zu werden. 
Das wäre aber weder zeitgemäß, noch komfortabel oder besonders effizient. Heute setzt man auf eine starke Entwicklungsumgebung. Google selbst unterstützt hier mit zahlreichen Erweiterungen (PlugIns) die Entwicklungsumgebung Eclipse, eine der meist verbreiteten IDEs (Integrated
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
5 
Development Enviroment) gerade in der Java Entwicklung. Eclipse ist ebenfalls Opensource und damit kostenlos. Dies bietet sehr viel Flexibilität und Erweiterungsmöglichkeiten. (Kurzer Einblick in Eclipse unter, 7.1 Eclipse Workbench, im Anhang auf Seite 37 ) 
Um nun mit der Entwicklung beginnen zu können benötigt man lediglich: 
• Eclipse http://www.eclipse.org/downloads/ 
• Android SDK (Service Development Kid) 
http://developer.android.com/sdk/index.html 
• ADT (Android Development Tools) Eclipse Plugin 
http://developer.android.com/tools/sdk/eclipse-adt.html 
Das ADT beinhaltet, neben vielen kleinen Hilfen wie einen grafischen Editor für die Benutzeroberfläche, auch einen Emulator, welcher ein beliebiges Android System emulieren kann und so ein schnelles Testen während der Entwicklung auch ohne Endgerät ermöglicht. Man kann sich mehrere verschiedene virtuelle Geräte konfigurieren und so verschiedene Displaygrößen und andere Hardwareeigenschaften emulieren und testen. 
2.3 Google ADT 
Das Plugin bietet viele nützliche Dienste und Hilfen. Hier die wichtigsten: 
• Assistent zum Erstellen eines neuen Android Projektes 
• Assistent zum Erstellen von Attributen und Variablen 
• Visueller Editor für die Benutzeroberfläche der App 
• Einfaches Verwalten und Starten des Emulators 
• Ausgabe vom Systemlog-Meldungen (Logcat) des Android Systems auf dem Emulator 
• Android SDK Manager (Verwaltet und hält SDK aktuell)
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
6 
Android API und Besonderheiten 
Die Google API (Application Programming Interface) stellt die zentrale Programmierschnittstelle dar. Ohne diese ist keine Entwicklung einer Android- App möglich, da bereits bei der Darstellung bis hin zur Interaktion mit dem Nutzer über das Touchscreen native Android-Funktionen benötigt werden. Es reicht also nicht aus Java entwickeln zu können, sondern es ist zwingend notwendig sich mit der Android API auseinander zu setzen und sich an deren Regeln zu halten. 
Die API existiert bisher in verschiedenen Versionen. Leider sind hier nicht alle Funktionen abwärtskompatibel, was es zwingend erforderlich macht Android mitzuteilen gegen welche API Version die App kompiliert ist. 
Dies geschieht in der AndroidManifest.xml. Hier wird die minimale API Anforderung und die zuletzt getestete API angegeben gegen die auch kompiliert wurde. Ist die angegebene „Minimum Required SDK“ neuer als die auf dem Installationsgerät so kann die Applikation dort nicht installiert werden. Fehlt diese Angabe kann die Applikation zwar installiert werden es wird aber womöglich zu Problemen bei der Ausführung kommen und damit zu schlechten Bewertungen im Play Store.
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
7 
Abbildung 1- Eclipse New Android Application
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
8 
2.4 Grober Aufbau einer Android App 
Grundsätzlich ist es jedem Entwickler frei gestellt wie er seine Anwendung gestaltet und entwickelt. Android oder die API machen hier keine Vorgaben sondern sind extrem flexibel in der Wahl der Softwarearchitektur. So können bestimmte Probleme mittels XML oder direkt im Java Code gelöst werden. 
Google treibt aber eine modulare Softwarearchitektur voran für ein modulares Bestriebssystem. Und nur das macht auch Sinn. Die Vorteile von, im weitesten Sinne losgelösten Einzelmodulen welche als Gesamtpaket eine Applikation bilden, liegen auf der Hand. Hier wird nicht nur die einfachere Entwicklung im Team oder Softwarepflege vereinfacht, sondern auch eine stabilere und schnellere Ausführung der Applikation für das Android System ermöglicht. XML- Dateien beispielsweise welche bestimmte Eigenschaften oder das Aussehen der Applikation beschreiben, werden vor der eigentlichen Codeausführung geladen und zwar schnell und stabil. Genauso gut könnte man die komplette View, also das Aussehen, im Java-Code schreiben. Das wäre aber nicht nur schlechter Stil, sondern würde auch zu Lasten der Performance gehen im Vergleich zu dem XML-Layout. 
In der Softwareentwicklung gibt es bestimmte Entwurfs- oder Architekturmuster darunter auch das „Model View Controller“ Modell. Dieses Modell lässt sich auch auf Android Applikationen anwenden und beschreibt eine klare Trennung der angesprochenen drei Bereiche. Während das „Model“ den Businessbereich und die Logik darstellt ist die „View“ für das Aussehen und die Interaktion mit dem Anwender zuständig. Der „Controller“ kontrolliert nun die Nutzung des „Models“ von der „View“ aus und weiß welche „View“ welches „Model“ verwendet.
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
9 
Vereinfachte Schematische Darstellung: 
Activity.XML - VIEW 
Activity.JAVA - Controller 
PlainOldJavaObject – Model 
Zusätzlich gibt es noch eine Persistenzschicht zur dauerhaften Datenspeicherung in einer Datenbank. Im Fall von Android sind das SQLite Datenbanken welche ganz einfach über die API angelegt und genutzt werden können. Und das ist im Groben auch alles was eine Android App heute nutzt um seine Aufgaben erfüllen zu können. Im nachfolgenden Kapitel werde ich hier noch etwas mehr ins Detail gehen. 
Abbildung 2- MVC Architektur Quelle: wikipedia.de (MVC)
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
10 
2.5 Grundlagen der Android Entwicklung 
2.5.1 View-Activity-Event-Intent 
Activity 
Die Activity stellt so zu sagen das Herzstück der Android Applikation dar mit dem entscheidenden Programmcode welcher für die Ausführung der Aplikation verantwortlich ist. Jede App muss mindestens eine Activity haben und eine davon muss als Hauptactivity definiert sein. Also die, welche beim Starten der App als erstes geladen und ausgeführt wird (Equivalent zur Main Methode eines klassischen Java-Programmes). Die Activity definiert eine „View“ zur Anzeige auf dem Bildschirm und behandelt dort auftretende Events wie beispielsweise ein Klick auf einen Button. Die Activity benutzt „Intents“ um andere Activitys zu starten. 
View 
Die View ist der sichtbare Teil der Activity und wird üblicherweise in einer XML- Layout-Datei definiert. 
Event 
Ein Event wird ausgelöst, wenn etwas geschieht wie das Klicken auf einen Button oder das Drücken des Suchen und Zurück Buttons. In der Activity muss dann ein Listener definert sein welcher auf diese Events reagiert und entsprechende Operationen durchführt. 
Intent 
Startet eine andere Activity also eine zweite Benutzeroberfläche auf dem Bildschirm. Mittels „Bundels“ können dann einfache Parameter an die Activity übergeben werden. Es können sogar Activities aus anderen Apps gestartet werden so lange diese verfügbar und im Android System als öffentlich gekennzeichnet sind. Beispielsweise könnte die Google Maps App gestartet werden und Koordinaten übergeben werden.
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
11 
Abbildung 3- Zusammenarbeit Activity und View (Quelle http://www.androidpit.de/de/android/wiki/view/Android_Anf%C3%A4nger_Workshop)
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
12 
2.5.2 Activity Lebenszyklus 
Da auf dem Handy die Ressourcen limitiert sind muss das Betriebssystem in der Lage sein auf den Lebenszyklus der Apps Einfluß nehmen zu können. Jede Activity hat ihren eigenen Lebenszyklus und so muss sich der Entwickler auch um die entprechenden Phasen des Zyklusses kümmern um Datenverluste oder unerwünschtes Verhalten zu vermeiden. Es gibt folgende Phasen: 
• onCreate() 
• onStart() 
• onPause() 
• onResume() 
• onStop() 
• onRestart() 
• onDestroy() 
Jede eigene Activity erbt diese Methoden von ihrer Vaterklasse Activity und kann diese überschreiben. OnPause() beispielsweise tritt ein wenn die Activity in den Hintegrund gerät weil ein Anruf herein kommt oder eine neue Activity aufgerufen wird. Vielleicht wäre es hier sinnvoll die bereits eingegebenen Daten in einer Datenbank zu speichern und bei onResume() wieder anzuzeigen. Folgendes Schaubild soll die verschiedenen Stati verdeutlichen:
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
13 
Abbildung 4 - Activity Lebenszyklus (Quelle http://www.androidpit.de/de/android/wiki/view/Android_Anf%C3%A4nger_Workshop)
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
14 
2.5.3 Die wichtigsten XML Dateien ausserhalb der Layouts 
Strings.xml 
Hier werden Variablen zur Darstellung definiert. Beispielsweise Beschriftungen und Text für die Buttons in den Views, Hilfemeldungen oder sonstige Texte. 
Android Manifest.xml 
Ist die Grundlage jeder App und unabdingbar. Hier werden Metainformationen wie das Icon, der Applikationsname und die Rechte, welche sich die Applikation einräumt, bekannt gegeben. Diese werden dem Nutzer auch vor der Installation bekannt gegeben und müssen bestätigt werden. Rechte sind beispielsweise Zugriffe auf das Netzwerk, die Kamera oder die Kontaktdaten. 
Ausserdem sollte noch die vorausgesetzte API Version angegeben werden, um zu verhindern, dass die App auf nicht lauffähigen Geräten installiert werden kann. 
Exemplarisches Beispiel einer AdroidManifest.xml mit Erläuterung. 
Abbildung 5- AndroidManifest.xml (Quelle http://www.androidpit.de/de/android/wiki/view/Android_Anf%C3%A4nger_Workshop/)
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
15 
2.5.4 Persistenz und Datenspeicherung in Adnroid 
Zur persistenten Datenspeicherung bietet Android eine einfache Art SQLite als schlankes Datenbanksystem an. Durch das Erben und Überschreiben der Klasse SQLiteOpenHelper wird es erleichtert eigene Datenbanken an zu legen, welche dann per default als Datei auf der SD-Karte gespeichert werden. 
SQLite ist eine Open-Source-Datenbank, die in Android eingebettet ist. SQLite unterstützt Standardfunktionen von relationalen Datenbanken wie SQL-Syntax, Transaktionen und Prepared Statements. Darüber hinaus bedarf es nur wenig Speicher zur Laufzeit (ca. 250 KByte). SQLite unterstützt die Datentypen TEXT (ähnlich String in Java), INTEGER (ähnlich wie long in Java) und REAL (ähnlich wie double in Java). Alle anderen Formate müssen vor dem Speichern in einen dieser Datentypen konvertiert werden.
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
16 
3 Kapitel 2 - App Dokumentation LittleProjectManager 
3.1 Beschreibung der Applikation 
Die App soll eine einfache Verwaltung von Projekten und seinen ToDo`s möglich machen. Zusätzlich soll man die Zeit messen können wie lange man für das jeweilige Projekt gearbeitet hat. Der Anwendungsfall kommt aus der Praxis. Denn bei kleinen oder mittelgroßen Projekten wird häufig vergessen die eigene Zeit zu messen um hinterher die geschätzte Zeit und die verbrauchte Zeit gegenüber stellen zu können. Ausserdem soll es helfen dem Kunden die korrekten Zeiten in Rechnung zu stellen. Die Möglichkeit ToDo`s anzulegen dient lediglich der Übersichtlichkeit und stellt eine Art Notizzettel für das Projekt dar. Ich habe mich bewusst dagegen entschieden die Zeiten für einzelne ToDos zu tracken. Dies wäre zwar auf Grund der Datenbankstruktur möglich findet aber in der Praxis wenig Relevanz da zumindest bei den Projekten kleinerer Größenordnung diese Zeiten keine Rolle spielen und das Buchen für den Nutzer zu aufwendig wäre. 
Die Applikation bildet folgende funktionale und technische Leistungsmerkmale: 
• Projekte anlegen und entfernen 
• ToDo`s für Projekte anlegen und entfernen 
• Einfaches „Einbuchen“ bei Arbeitsbeginn 
• Einfaches „Ausbuchen“ bei Arbeitsende 
• Zusätzlich soll auch ein manuelles Buchen von Zeiten möglich sein 
• Die App soll direkt nach Buchung die aktuelle Zeit berechnen und 
anzeigen 
Technische Leistungsmerkmale: 
• Daten in der SQLite Datenbank speichern 
• Intuitive Bedienung über das Touch-Display
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
17 
• Optimiert für die Benutzung mit Smartphone, sollte aber auch auf einem 
Tablet funktionsfähig sein 
• Android spezifische Bedienelemente wie der Zurück Button und Menü 
Button (vor Android 3.0) sollten unterstützt werden 
Screenshots zur Verdeutlichung finden sich im Anhang unter 7.2 Screenshots LittleProjectManager auf Seite 38.
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
18 
3.2 Architektur und Funktionsweise der Applikation 
Hierzu empfiehlt es sich erst mal einen Blick auf das Schaubild aus Anlage 7.3 Architekturschaubild auf Seite 40 zu werfen. Dort ist ein Architekturdiagramm der Applikation abgebildet unter Berücksichtigung des MVC Entwurfsmusters. Es beinhaltet alle funktional wichtigen Klassen und XML Dateien der Applikation und deren Abhängigkeiten, welche nun im Detail erläutert werden. Es empfiehlt sich vorher im ersten Kapitel den Teil „Grober Aufbau einer Android Applikation“ gelesen zu haben. 
3.2.1 Activity-View und Layout (VIEW) 
In der VIEW befinden sich die XML Dateien. Drei Activity-Views und ein Layout. 
Die activity_project_view und die activity_todo_view bestehen beide aus ListViews um eine Liste der jeweiligen Objekte, eben Projekte und Todos, darstellen zu können. Bei beiden kann über das Menü das Layout add_item.xml aufgerufen werden. Dies ist eine Art Formular, um neue Todo's oder Projekte an zu legen. Das Add-Item-Layout besteht aus einem Textfeld und einem Button und wird hier einmal exemplarisch dargestellt: 
<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
android:orientation="vertical" > 
<EditText 
android:id="@+id/editText1" 
android:layout_width="match_parent" 
android:layout_height="wrap_content" 
android:ems="10" 
android:inputType="textMultiLine" > 
<requestFocus /> 
</EditText>
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
19 
<Button 
android:id="@+id/button1" 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" 
android:text="@string/Add" 
android:onClick="AddClick" 
/> 
</LinearLayout> 
Das ganze Layout besteht aus einem LinearLayout innerhalb dessen befinden sich ein EditText Feld zum Eingeben des neuen Projektes oder des Todo und ein Button zum Bestätigen. Zusätzlich werden Angaben zur Größe und Anordnung des jeweiligen Elementes gemacht. Die android:id beschreibt den Namen über den auf das Element später im JAVA Code zugegriffen werden kann und android:text="@string/Add gibt an welcher Text auf dem Button stehen soll. 
Unter android:id="@+id/editText1" kann das Textfeld in der JavaKlasse also der jeweiligen Activity, welche das Layout gestartet hat, erreicht werden. Und android:onClick="AddClick" gibt an, dass, wenn der Button Add gedrückt wird, in der Activity die Methode AddClick() ausgeführt wird. 
Die Dritte und letzte Activity-View ist die activity_time_manager.xml welche für die Zeitbuchungen und die Anzeige der Zeiten zuständig ist. Dementsprechend viele Elemente sind hier vorhanden: 
 ein Button zur Anzeig des aktuellen Datums 
 ein Button welcher die aktuelle Zeit anzeigt 
 ein Button zum Einbuchen 
 ein Button zum Ausbuchen 
 einen Button um nur die Zeit in Stunden und Minuten auf das Projekt nachträglich als Arbeitszeit zu buchen. 
Wird der Button für Datum gedrückt so öffnet sich ein spezielles Auswahlmenü von Android zur Datumsauswahl und bei der Zeit ist es das gleiche. Diese Auswahldialoge müssen als so genannte Dialogfragmente ausprogrammiert
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
20 
werden. 
3.2.2 Activitys (Controller) 
Jede Activity-View hat auch ihre eigene Klasse welche die verschiedenen Stati des Lebenszyklus und die Interaktion mit dem Benutzer behandelt. Die Hauptactivity ist in der AndroidManifest.xml beschrieben. Bei dieser Applikation handelt es sich um die Activity Project_View.java. Jede Activity die als solche fungieren soll hat als Vaterklasse die Klasse android.app.Activity und überschreibt mindestens eine Methode: Die onCreate() Methode, welche in unserem Fall nichts weiter macht als sich aktuelle Daten aus der Datenbank zu holen und darzustellen. Zusätzlich wird noch das Optionsmenu deklariert und auf das Drücken von Menüeinträgen, Listeinträgen und Buttons mit entsprechendem Programmcode reagiert. 
ProjectView.java 
Füllt die ListView mit Projekten. Projekte können ausgewählt und anschließend gelöscht werden. Genauso gut können nach Auswahl eines Projektes die dazugehörigen Todos geladen werden. Dies geschieht durch das Aufrufen der MyTodosOverview und die Übergabe der Projektid des ausgewählten Objektes. Ausserdem kann das Layout add_item.xml aufgerufen werden und neue Projekte angelegt werden. 
Kurze Beschreibung der Methoden: 
onCreate() 
Legt die Activity-View fest welche angezeigt werden soll. 
Ruft Hilsmethode showValuesFromDB() auf. 
showValuesFromDB() 
Holt sich die Projekte aus der Datenbank und setzt vorhandene Values in die Liste.
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
21 
Aktiviert OnClickListner welcher das markierte Objekt der Liste festhält und einfärbt. 
onCreateOptionsMenu() 
Legt das Menü Fest welches angezeigt wird wenn auf den Menü Button gedrückt wird. 
onOptionsItemSelected(MenuItem item) 
Deklariert pro betätigtem Menüeintrag was passieren soll. 
AddClick(View view) 
Methode wird aufgerufen wenn im add_item.xml Layout der Button Add gedrückt wird. 
Der Inhalt des Textfeldes aus dem Layout wird als Projekt in die Datenbank geschrieben 
MyTodosOverview.java 
Funktioniert genauso wie die ProjectView.java, ausser dass es sich hierbei um die Todos handelt, die angezeigt, verwaltet und in die Datenbank geschrieben, sowie dort gelöscht werden können. 
TimeManager.java 
Diese Activity ist die Aufwendigste in der Applikation. Sie übernimmt nicht nur das Eintragen von Buchungen in die Datenbank sondern ist auch für die aktuelle Anzeige von Datum und Uhrzeit zuständig. Außerdem errechnet sie bei jeder Buchung die Arbeitszeit neu, sofern möglich und zeigt diese Information direkt über die VIEW an. Die beiden Dialoge zur Datums- und Zeitauswahl werden von ihr gestartet und beobachtet um Änderungen direkt zu erkennen. Daher handelt es sich auch um eine FragmentActivity welche ihrerseits erweiterte Funktionen anbietet als ihre Vaterklasse Activity.
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
22 
Die ganze Berechnung der Zeit erfolgt über ein java.util.Calendar Objekt während die Anzeige über java.text.SimpleDateFormat formatiert wird. 
Erläuterung der wichtigsten Methoden: 
onCreate() 
Legt die Activity-View fest welche angezeigt werden soll. 
Ermittelt die aktuelle Zeit 
Steuert die interne Hilfsmethode setTimeOnView(Calendar c) und setDateOnView(Calendar c) an. 
Steuert interne Hilfsmethode addTimeandDateButtonListners() an. 
onResume() 
Ermittelt das aktuelle Projekt und zeigt dessen Namen an sowie die bisher gebuchte Arbeitszeit. Dies geschieht in der onResume() Methode so, dass die Anzeige nicht nur nach dem Erstellen der Activity aktualisiert wird sondern auch wenn die Activity im Hintergrund war. 
setTimeOnView(Calendar c) 
Zeigt die aktuelle Zeit im Button an 
setDateOnView(Calendar c) 
Zeigt aktuelles Datum im Datum Button an 
addTimeandDateButtonListners() 
Listner welcher auf das Drücken einer der Buttons reagiert 
checkin(), checkout() und justbookthetime() 
Bucht die entsprechende Zeit in die Datenbank. 
Steuert CalcWorkingTime() an 
CalcWorkingTime() 
Errechnet die Arbeitszeit wenn möglich. Es wird überprüft ob genau so viele
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
23 
Ein- wie Ausbuchungen vorhanden sind, errechnet dann die neue Arbeitszeit und schreibt diese Informationen in die Datenbank. 
ShowDatePicker() und showTimePicker() 
Zeigen die Dialoge zur Auswahl von Datum und Zeit an 
OnTimeSetListener() und OnDateSetListener() 
Reagieren auf die Zeitauswahl in dem sie die Zeit im Calendar Objekt ändern und die ausgewählte Zeiten auf den Buttons der View visualisieren. 
3.2.3 Dialogfragmente (Controller) 
Zur Auswahl von Datum und Zeit werden TimePicker und DatePicker verwendet. Dies sind Objekte um es dem Nutzer so komfortabel wie möglich zu machen über den Touchscreen Datum und Zeiteingaben zu tätigen. Diese werden von Android zur Verfügung gestellt. Um sie nutzen zu können, müssen sie in so genannte Dialogfragmente verpackt werden. Also Dialoge welche erscheinen während die eigentliche Activity im Hintergrund noch aktiv ist. Also weder in den Status onPause() gesetzt, noch beendet wird. Wird also nun in der Time_Manager.java Activity auf den Button mit dem Datum gedrückt so wird das DatePickerFragment gestartet. Über einen Datencontainer, bei Android das Bundle, werden die aktuellen Werte zur Anzeige übergeben und bei Auswahl durch den Nutzer die ausgewählten Werte zurück an die Activity übergeben.
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
24 
3.2.4 Plain-Old-Java-Objects (Model) 
Hier finden sich klassische Java Objekte welche in der Applikation durch alle Instanzen hindurch genutzt werden wie Todo, TimeEntry oder Project. Klassisch deshalb weil sie als Vaterklasse lediglich die Klasse Object besitzen. Diese Objekte stellen immer jeweils ein Listeneintrag in der View oder eine Zeile in der Datenbank dar. Dementsprechend sind auch die Attribute pro Klasse gewählt: 
3.2.5 DataAccessObjects (Model) 
Hierunter fallen die drei Klassen ProjectDatasource.java, TimeTableDatasource.java und TodosDatasource.java. Die Aufgabe des DAO ist das Erlauben des Zugriffs auf die Datenbank und das Anbieten von Methoden fürs Abholen und Schreiben von Daten. Dies beinhaltet den Verbindungsauf- und Abbau genauso wie das Zusammenbauen bestimmter SQL-Abfragen zum Herausholen aller oder nur eines bestimmten Datensatzes mittels Fremdschlüssel. Das Ergebnis aus der Datenbank kommt als so genannter Curser zurück und wird nicht einfach an die aufrufende Klasse zurückgegeben. Es werden POJOs (Plain-Old-Java-Objects) vom jeweiligen Typ erzeugt und einzeln oder in einer Liste zurück gegeben. Dazu wurden in 
Abbildung 6 - Klassendiagramm Models
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
25 
der Klasse als privat gekennzeichnete Hilfsmethoden geschrieben. 
3.2.6 MySQLiteHelper und seine Tabellenklassen (Model) 
MySQLiteHelper hat als Vaterklasse SQLiteOpenHelper und überschreibt onCreate() und onUpgrade(). OnCreate() wird vom Framework aufgerufen wenn die Datenbank noch nicht existiert und onUpdate() wenn sich die Versionsnummer ändert. Beide Methoden bekommen ein Datenbankobjekt beim Aufruf übergeben, welches die Datenbank repräsentiert. 
In der Applikation gibt es für jede Tabelle eine eigene Klasse: 
• ProjectTable.java 
• TodoTable.java 
• TimeTabl.java 
Jede dieser Tabellenklassen hat statische Variablen für den Tabellennamen und die Spalten. Ausserdem besitzt jede Klasse ihre eigene statische onCreate() und onUpdate() Methode in der der SQL-Befehl zum Erstellen und Updaten der Tabellen ausformuliert ist. Hier wird auch angegeben welche Datentypen in die Spalten gehören und ob es sich dabei um Schlüssel handelt. 
Als Beispiel hier ein Auszug der Klasse ProjectTable, welche auch genau diese Tabelle MYPROJECTS repräsentiert: 
public class ProjectTable 
// Database table 
public static final String TABLE_PJ = "myprojects"; 
public static final String COLUMN_ID = "_id"; 
public static final String COLUM_NAME = "name"; 
public static final String COLUM_WORKTIME = "worktime"; 
//SQL CREATE Statement 
private static final String TABLE_CREATE_MYPROJECTS ="" 
+"create table " +TABLE_PJ +" ( " 
+COLUMN_ID+ " integer primary key autoincrement, " 
+COLUM_NAME +" text not null, " 
+COLUM_WORKTIME +" integer" 
+");"; 
/*
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
26 
* Tabelle erstellen 
*/ 
public static void onCreate(SQLiteDatabase db) { 
db.execSQL(TABLE_CREATE_MYPROJECTS); 
} 
Es wird von Android empfohlen als Primärschlüssel _id zu verwenden so wie hier geschehen. Zusätzlich wird noch durch „autoincrement“ angegeben, dass die Spalte automatisch hoch gezählt wird. 
Die Klasse MySQLiteHelper führt jetzt in seiner eigenen onCreate() Methode nur noch die statischen onCreate() Methoden der jeweiligen Tabellen aus: 
Auszug aus public class MySQLiteHelper 
@Override 
public void onCreate(SQLiteDatabase db) { 
ProjectTable.onCreate(db); 
TodoTable.onCreate(db); 
TimeTable.onCreate(db); 
} 
So ist sichergestellt, dass die Datenbanken alle angelegt sind und von Objekten der Datasource Klasse darauf zu gegriffen werden kann. 
3.3 SQLite Datenbank 
Zur Datenspeicherung bietet Android eine sehr einfache Möglichkeit eine SQLite Datenbank an zu legen. Der LittleProjektManager greift darauf zu. Die Daten werden zwecks Normalisierung und einer einfachen Datenhaltung in drei Tabellen gespeichert. Android empfiehlt für jede Tabelle eine Spalte _id als Primärschlüssel zu verwenden. In unserem Falle deklarieren wir die Spalte _id zusätzlich noch als „autoincrement“, so dass sie bei jedem Eintrag automatisch hoch gezählt wird und uns die Verknüpfung somit vereinfacht. In SQLite gibt es vier Datentypen:
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
27 
SQLite Datentyp Equivalent in JAVA 
INTEGER 
Long 
TEXT 
String 
REAL 
Double 
BLOB 
Data 
Die Datenbank selbst wird von Android auf der SD-Karte unter dem Ordner „data“ und dem jeweiligen Applikationsnamen als eine Datei gespeichert. 
3.3.1 Datenbankstruktur 
Abbildung 7 - Datenbankdiagramm 
MYPROJECTS 
Beinhaltet alle relevanten Informationen zum Projekt. Der eingegebene Name als Text, eine _id als Primärschlüssel, der automatisch hoch gezählt wird und die workingtime als Integer. Die Workingtime ist zu Beginn 0 und wird dann je nach Buchungen hochgezählt und überschrieben. Einfache Zeitbuchen werden direkt und nur hier gespeichert. Ein- und Ausbuchungen mit Datumsangaben kommen in die Tabelle TIMETABLE. 
TODO
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
28 
Ist eine unabhängige Tabelle mit eigener _id als Primärschlüssel und der Aufgabe todo selbst als Text. Da alle Todos einem Projekt zugeordnet werden müssen, sind sie über die pj_id als Fremdschlüssel mit der Tabelle MYPROJECTS verbunden. Es besteht eine 1-zu-n Beziehung. Ein Projekt kann viele Todos haben aber ein Todo kann nur zu einem Projekt gehören. 
TIMETABLE 
Hier werden alle Ein- und Ausbuchungen gespeichert, welche nicht nur als Zeitbuchung, sondern mit einer kompletten Zeitangabe gebucht werden also Datum und Uhrzeit. Beides zusammen wird im Java Code als Ganzzahl im Datentyp long dargestellt und kann daher auch so in der Datenbank eingetragen werden. Neben dem Primärschlüssel _id wird die Zeit als long, und datetime als Integer gespeichert. Unter entrytype wird eine 0 fürs Einbuchen und eine 1 fürs Ausbuchen geschrieben und die pj_id ist wieder die Verbindung in Form eines Fremdschlüssels zur Tabelle MYPROJECTS. Auch hier besteht vom Projekt der Tabelle MYPROJECTS ausgehend eine 1-zu-n Beziehung.
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
29 
3.4 Projekt und Paketstruktur 
3.4.1 Pakete und Klassen 
Da der Paketname eindeutig für die Applikation sein soll, um gezielt der eigenen Applikation zugeordnet werden zu können, wurde hier de.thorstenweiskopf.lpm gewählt. Das Kürzel de für die Länderdomäne, thorstenweiskopf als autor und lpm als kürzel für den Applikationsname LittleProjectManager. Danach werden noch Unterpakete verwendet um die unterschiedlichen Aufgabenbereiche darzustellen:
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
30 
src: Hier liegen die eigenen Klassen. 
Unter dem Hauptpaket befinden sich die drei Activitys. 
.databse: 
alle datenbankrelevanten Klassen: 
Der SQLiteHelper welcher die Datenbank erstellt und updatet sowie die drei Datasources zum Zugriff auf die Datenbank. 
.tables: 
Tabellen selbst in Form von Java- Klassen die vom SQLiteHelper genutzt werden. 
.dialogframents 
ZeitAuswahlDialoge 
.model 
Daten Modelle für die verwendeten Datenobjekte: Projekt, Zeiteintrag und Todo. 
gen: Hier sind die von Android generierten Klassen abgelegt. Am wichtigsten ist die Klasse R welche über Referenzvariablen alle Ressourcen zur Verfügung stellt. Ressourcen sind: Layouts, Activity-Views, Strings, Menüs, Bilder usw.
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
31 
3.4.2 Projektdateien und Ressourcen 
Das Android Projekt besteht allerdings aus mehr als nur den Java-Klassen selbst. Es gibt noch ein Ressourcen Verzeichnis mit Inhalten und die AndroidManifest.xml:
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
32 
/res:Ordner für Resource-Dateien 
/res/drawable-hdpi: Logos in hoher Auflösung 
/res/drawable-ldpi Logos in niedriger Auflösung 
/res/drawable-mdpi: Logos in mittlerer Auflösung 
/res/drawable-xhdpi:Logos in sehr hoher Auflösung 
/res/layout 
alle Layout-Definitionen 
Activity-Views und Layouts 
/res/menu: Menüs 
activity_project_view: Menü für die Projektübersicht 
activity_project_view: Menü für die ToDos 
/res/values: Variablen 
strings.xml: String-Definitionen für Buttons und Überschriften 
styles.xml: Erscheinungsbild der App 
AndroidManifest.xml:"Manifest"-Datei, definiert Infos wie Name, Logo und Haupt-Activity 
default.properties:Projekt-Eigenschaften
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
33 
4 Ausblick und Fazit 
Die Applikation „LittleProjektMananer“ hat noch Optimierungspotential hinsichtlich des Designs. Ausserdem fehlt noch eine Implementierung der seit Android 4.0 vorhandenen „ActionBar“ welche das Menü ersetzen soll. Eine Möglichkeit für statistische Auswertungen über die bereits getätigten Buchungen ist auch denkbar. Sind diese Leistungsmerkmale realisiert, was sich bereits in Planung befindet, steht einer Veröffentlichung über den Google „Playstore“ nichts mehr im Wege. 
Als Fazit für Android selbst ist zu sagen, dass Android eine solide Basis bietet native Applikationen zu entwickeln. Der modulare Aufbau bietet gute Möglichkeiten für Erweiterungen und die Realisierung von größeren Projekten. Diese Gründe und der Fakt, dass das Betriebssystem auf dem Vormarsch in vielen Bereichen elektronischer Geräte ist, verspricht Android und den Applikationsentwicklern eine aussichtsreiche Zukunft.
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
34 
5 Abbildungsverzeichnis 
Abbildung 1 - Eclipse New Android Application .................................................. 7 
Abbildung 2 - MVC Architektur ........................................................................... 9 
Abbildung 3 - Zusammenarbeit Activity und View ........................................... 11 
Abbildung 4 - Activity Lebenszyklus ............................................................... 13 
Abbildung 5 - AndroidManifest.xml ................................................................. 14 
Abbildung 6 - Klassendiagramm Models .......................................................... 24 
Abbildung 7 - Datenbankdiagramm .................................................................. 27
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
35 
6 Abkürzungsverzeichnis 
App 
Application (Anwendung) 
IDE 
Integrated Development Enviroment 
SDK 
Service Development Kit 
ADT 
Android Development Tools 
API 
Application Programming Interface 
MVC 
Model View Controller (Softwarearchitektur) 
POJO 
Plain Old Java Object (“simple” Javaklassen)
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
36 
7 Anlagen
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
37 
7.1 Eclipse Workbench 
(QUELLE: http://www.admin-wissen.de/tutorials/eclipse_workshop/ueberblick_workbench.html) 
Zu Eclipse selbst und der Benutzung gibt es eine Reihe von Büchern und Seminare. Ich möchte hier nur einen Auszug aus www.admin-wissen.de einbinden welcher ganz gut die Benutzung erläutert: 
1. Im Bereich 1 findest einen Überblick über die vorhandenen Projekte. Du kannst zwischen den Projekten navigieren und Dateien öffnen, erstellen oder Ordner in denProjekten anlegen etc. 
2. In diesem Bereich ist der Editor zu finden. Im Editor kannst du den Sourcecode schreiben, er wird farbig hervorgehoben und Fehler die Eclipse im Vorfeld erkennt werden markiert. In manchen Fällen signalisiert Eclipse mit einer Glühbirne, wie der Fehler möglicherweise behoben werden kann. 
3. Hier befindet sich die Outline. Darin findest du wissenswertes über die im Moment geöffnete Datei. Bei einer Klasses siehst du hier die Attribute und Methoden und kannst sie sortieren oder anders in der Outline organisieren. Durch einen Klick auf die Methode kommst du z.B. direkt an die Stelle im Quelltext wo sie implementiert ist. Dadurch bekommt man bei umfangreichen Klassen schnell einen Überblick welche Methoden die Klasse bietet. 
4. In diesem Bereich findest du verschiedene Konsolenausgaben. Eine mögliche Konsolenausgabe ist z.B. ein Kompilierungsfehler oder die Ausgabe des laufenden Programms.
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
38 
7.2 Screenshots LittleProjectManager 
Projektübersicht 
Projektübersicht mit Auswahl und Menü 
Add Item Formular 
Todoübersicht mit Auswahl und Menü
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
39 
Arbeitszeitverwaltung zum Buchen und Anzeigen von Zeiten 
Dialog zur Zeitauswahl wenn entsprechender Button gedrückt wurde
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
40 
7.3 Architekturschaubild
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
41 
7.4 Quellcode der Applikation 
AndroidManifest.xml 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
package="de.thorstenweiskopf.lpm" 
android:versionCode="1" 
android:versionName="1.0" > 
<!-- welches min und max sdk wird supported von dieser app --> 
<uses-sdk 
android:minSdkVersion="8" 
android:targetSdkVersion="15" /> 
<!-- applicationbeschreibung--> 
<application 
android:icon="@drawable/ic_launcher" 
android:label="@string/app_name" 
android:theme="@style/AppTheme" > 
<!-- alle Activitys also Views --> 
<activity 
android:name=".MyTodosOverview" 
android:label="@string/title_activity_my_todos_overview" > 
</activity> 
<activity 
android:name=".ProjectView" 
android:label="@string/title_activity_project_view" 
android:configChanges="orientation|keyboardHidden|keyboard|screenSize" > 
<intent-filter> 
<!-- Hauptactivity soll geöffnet werden beim start --> 
<action android:name="android.intent.action.MAIN" /> 
<category android:name="android.intent.category.LAUNCHER" /> 
</intent-filter> 
</activity> 
<activity 
android:name=".TimeManager" 
android:label="@string/title_activity_time_manager" > 
</activity> 
</application> 
</manifest>
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
42 
stringx.xml 
<resources> 
<string name="app_name">LittleProjectManager</string> 
<string name="title_activity_my_todos_overview">My Todos</string> 
<string name="Add">Add</string> 
<string name="Remove">Remove</string> 
<string name="title_activity_my_todo_add">Add a Todo</string> 
<string name="title_activity_project_view">My Projects</string> 
<string name="title_activity_time_manager">My Project Times</string> 
<string name="menu_settings">Settings</string> 
<string name="menu_addpj">Add Project</string> 
<string name="menu_showtodos">Show ToDo Items</string> 
<string name="menu_remove_pj">Remove Project</string> 
<string name="menu_timemanager">Project TimeManagement</string> 
<string name="menu_timestats">Show Workingtime</string> 
<string name="time_checkinbutton">Check In</string> 
<string name="time_checkoutbutton">Check Out</string> 
<string name="time_hourbutton">Timebooking (Hour and Minute)</string> 
</resources>
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
43 
ACTIVITY-VIEWS 
activity_project_view.xml 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:tools="http://schemas.android.com/tools" 
android:layout_width="match_parent" 
android:layout_height="match_parent" > 
<ListView 
android:id="@+id/listView1" 
android:layout_width="match_parent" 
android:layout_height="wrap_content" > 
</ListView> 
</RelativeLayout> 
activity_todos_view.xml 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:orientation="vertical" 
android:layout_width="fill_parent" 
android:layout_height="fill_parent"> 
<LinearLayout 
android:layout_height="wrap_content" 
android:layout_width="wrap_content" > 
<TextView 
android:id="@+id/todo_lable" 
android:layout_width="match_parent" 
android:layout_height="wrap_content" 
android:text="@string/title_activity_my_todos_overview" 
android:textSize="30dp" /> 
</LinearLayout> 
<LinearLayout 
android:layout_height="match_parent" 
android:layout_width="match_parent" > 
<ListView 
android:id="@+id/listView1" 
android:layout_width="match_parent" 
android:layout_height="wrap_content" > 
</ListView> 
</LinearLayout> 
</LinearLayout>
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
44 
additem.xml 
<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
android:orientation="vertical" > 
<EditText 
android:id="@+id/editText1" 
android:layout_width="match_parent" 
android:layout_height="wrap_content" 
android:ems="10" 
android:inputType="textMultiLine" > 
<requestFocus /> 
</EditText> 
<Button 
android:id="@+id/button1" 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" 
android:text="@string/Add" 
android:onClick="AddClick" 
/> 
</LinearLayout>
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
45 
activity_time_manager_view.xml 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="fill_parent" 
android:layout_height="fill_parent" 
android:orientation="vertical" > 
<TextView 
android:id="@+id/Text_ProjectLable" 
android:layout_width="match_parent" 
android:layout_height="wrap_content" 
android:layout_marginLeft="5dip" 
android:text="Large Text" 
android:textAppearance="?android:attr/textAppearanceLarge" 
android:textSize="30dp" /> 
<TextView 
android:id="@+id/Text_ProjectTime" 
android:layout_width="match_parent" 
android:layout_height="wrap_content" 
android:layout_margin="10dip" 
android:text="Large Text" 
android:textAppearance="?android:attr/textAppearanceLarge" /> 
<Button 
android:id="@+id/button_date" 
android:layout_width="199dp" 
android:layout_height="wrap_content" 
android:layout_gravity="center_horizontal" 
android:layout_marginTop="5dip" 
android:text="Button" /> 
<LinearLayout 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" 
android:layout_gravity="center" 
android:orientation="horizontal" > 
<Button 
android:id="@+id/button_time" 
android:layout_width="198dp" 
android:layout_height="wrap_content" 
android:text="Button" /> 
</LinearLayout> 
<LinearLayout 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" 
android:layout_gravity="center_horizontal" > 
<Button 
android:id="@+id/button_checkin" 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" 
android:layout_gravity="center_vertical" 
android:layout_margin="10dip" 
android:text="@string/time_checkinbutton" />
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
46 
<Button 
android:id="@+id/button_checkout" 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" 
android:layout_margin="10dip" 
android:text="@string/time_checkoutbutton" /> 
</LinearLayout> 
<Button 
android:id="@+id/button_hours" 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" 
android:layout_gravity="center" 
android:text="@string/time_hourbutton" /> 
</LinearLayout>
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
47 
MENUS 
acitivity_project_view 
<menu xmlns:android="http://schemas.android.com/apk/res/android"> 
<item android:id="@+id/addpj" android:title="@string/menu_addpj"></item> 
<item android:id="@+id/showTodos" android:title="@string/menu_showtodos"></item> 
<item android:id="@+id/removepj" android:title="@string/menu_remove_pj"></item> 
<item android:id="@+id/timemanager" android:title="@string/menu_timemanager"></item> 
</menu> 
activity_todos_view 
<menu xmlns:android="http://schemas.android.com/apk/res/android"> 
<item android:id="@+id/addpj" android:title="@string/menu_addpj"></item> 
<item android:id="@+id/showTodos" android:title="@string/menu_showtodos"></item> 
<item android:id="@+id/removepj" android:title="@string/menu_remove_pj"></item> 
<item android:id="@+id/timemanager" android:title="@string/menu_timemanager"></item> 
</menu>
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
48 
JAVA KLASSEN 
MyTodosOverview.java 
package de.thorstenweiskopf.lpm; 
import java.util.ArrayList; 
import java.util.List; 
import de.thorstenweiskopf.lpm.database.TodosDatasource; 
import de.thorstenweiskopf.lpm.model.ToDo; 
import de.thorstenweiskopf.lpm.R; 
import android.os.Bundle; 
import android.app.Activity; 
import android.graphics.Color; 
import android.view.Menu; 
import android.view.MenuItem; 
import android.view.View; 
import android.widget.AdapterView; 
import android.widget.AdapterView.OnItemClickListener; 
import android.widget.ArrayAdapter; 
import android.widget.EditText; 
import android.widget.ListView; 
import android.widget.TextView; 
import android.widget.Toast; 
public class MyTodosOverview extends Activity { 
ArrayAdapter<ToDo> adapter; 
//Variablen der Todo Liste 
public static List<ToDo> values = new ArrayList<ToDo>(); 
int selectedItem = -999; 
private String projectname; 
private long projectid; 
//For Database Use 
private TodosDatasource datasource; 
@Override 
public void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.activity_todos_view); 
//Datasource benutzen 
datasource = new TodosDatasource(this); 
Bundle extras = getIntent().getExtras(); 
if (extras == null) { 
return; 
} 
// Get data via the key from Intent 
projectname = extras.getString("ProjectName"); 
projectid = extras.getLong("ProjectId"); 
if (projectname != null) { 
// Show projectname as lable
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
49 
TextView lable = (TextView) findViewById(R.id.todo_lable); 
lable.setText(projectname); 
} 
showValuesFromDB(projectid); 
} 
/* 
* Methode um mittels projectid die entsprechenden Todos anzuzeigen 
*/ 
private void showValuesFromDB(long projectid) { 
values.clear(); 
try { 
datasource.open(); 
values = datasource.getAllTodosFromProject(Long.toString(projectid)); 
datasource.close(); 
} catch (Exception ex) { 
Toast.makeText(this, ex.toString(), Toast.LENGTH_LONG).show(); 
} 
adapter = new ArrayAdapter<ToDo>(this, 
android.R.layout.simple_list_item_1, android.R.id.text1, values); 
// Assign adapter to ListView 
ListView listView = (ListView) findViewById(R.id.listView1); 
listView.setAdapter(adapter); 
//Set a OnClickListner to the ListView to choose one todo 
listView.setOnItemClickListener(new OnItemClickListener() { 
public void onItemClick(AdapterView<?> parent, View view, 
int position, long id) { 
selectedItem = position; //the choosen one 
//change bgcolor of the selected item 
for(int a = 0; a < parent.getChildCount(); a++) 
{ 
parent.getChildAt(a).setBackgroundColor(Color.WHITE); 
} 
view.setBackgroundColor(Color.GRAY); 
openOptionsMenu(); 
} 
}); 
} 
/* 
* Methode setzt alle vorhandene Todos in die Liste 
* DERZEIT nicht genutzt 
*/ 
private void showValuesFromDB() { 
values.clear(); 
try { 
datasource.open(); 
values = datasource.getAllTodos(); 
datasource.close(); 
} catch (Exception ex) { 
Toast.makeText(this, ex.toString(), Toast.LENGTH_LONG).show(); 
} 
adapter = new ArrayAdapter<ToDo>(this, 
android.R.layout.simple_list_item_1, android.R.id.text1, values); 
// Assign adapter to ListView 
ListView listView = (ListView) findViewById(R.id.listView1);
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
50 
listView.setAdapter(adapter); 
//Set a OnClickListner to the ListView to choose one todo 
listView.setOnItemClickListener(new OnItemClickListener() { 
public void onItemClick(AdapterView<?> parent, View view, 
int position, long id) { 
selectedItem = position; //the choosen one 
//change bgcolor of the selected item 
for(int a = 0; a < parent.getChildCount(); a++) 
{ 
parent.getChildAt(a).setBackgroundColor(Color.WHITE); 
} 
view.setBackgroundColor(Color.GRAY); 
openOptionsMenu(); 
} 
}); 
} 
/* 
* (non-Javadoc) 
* @see android.app.Activity#onCreateOptionsMenu(android.view.Menu) 
* OptionsMenuStuff 
*/ 
@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
getMenuInflater().inflate(R.menu.activity_todos_view, menu); 
return true; 
} 
@Override 
public boolean onOptionsItemSelected(MenuItem item) { 
if (item.getItemId() == R.id.Add){ 
ListView listView = (ListView) findViewById(R.id.listView1); 
listView.setAdapter(adapter); 
// show the add view 
setContentView(R.layout.additem); 
} else if (item.getItemId() == R.id.Remove) { 
if (selectedItem != -999){ 
ToDo todo = adapter.getItem(selectedItem); 
selectedItem = -999; 
try { 
datasource.open(); 
datasource.removeTodo(todo); 
datasource.close(); 
} catch (Exception ex) { 
Toast.makeText(this, ex.toString(), Toast.LENGTH_LONG) 
.show(); 
} 
// show the main view 
setContentView(R.layout.activity_todos_view); 
showValuesFromDB(); 
} 
else{ 
Toast.makeText(this, "Please choose a Item from List", Toast.LENGTH_LONG).show(); 
} 
}
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
51 
return super.onOptionsItemSelected(item); 
} 
/* 
* Method of the layout additem.xml 
* Beschrieben im Layout als AddClick 
*/ 
public void AddClick(View view){ 
if (view.getId() == R.id.button1){ 
EditText text = (EditText)findViewById(R.id.editText1); 
//values.add(text.getText().toString()); 
//put the new value in the database 
try { 
datasource.open(); 
datasource.creatTodo(text.getText().toString(), Long.toString(projectid));//Fehlt noch die Projektid vom DB Objekt Projekt 
datasource.close(); 
} catch (Exception ex) { 
Toast.makeText(this, ex.toString(), Toast.LENGTH_LONG).show(); 
} 
//show the main view 
setContentView(R.layout.activity_todos_view); 
// Show projectname as lable 
TextView lable = (TextView) findViewById(R.id.todo_lable); 
lable.setText(projectname); 
showValuesFromDB(projectid); 
} 
} 
}
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
52 
ProjectView.java 
package de.thorstenweiskopf.lpm; 
import java.util.ArrayList; 
import java.util.List; 
import de.thorstenweiskopf.lpm.database.ProjectDatasource; 
import de.thorstenweiskopf.lpm.database.TodosDatasource; 
import de.thorstenweiskopf.lpm.model.Project; 
import de.thorstenweiskopf.lpm.model.ToDo; 
import de.thorstenweiskopf.lpm.R; 
import android.os.Bundle; 
import android.app.Activity; 
import android.content.Intent; 
import android.graphics.Color; 
import android.view.Menu; 
import android.view.MenuItem; 
import android.view.View; 
import android.widget.AdapterView; 
import android.widget.ArrayAdapter; 
import android.widget.EditText; 
import android.widget.ListView; 
import android.widget.Toast; 
import android.widget.AdapterView.OnItemClickListener; 
public class ProjectView extends Activity { 
ArrayAdapter<Project> adapter; //Adapter to fill the P 
//Variablen der Projekte Liste 
public static List<Project> values = new ArrayList<Project>(); 
int selectedItem = -999; 
private ProjectDatasource datasource; //Schnittstelle zur Datenbank 
/* 
* (non-Javadoc) 
* @see android.app.Activity#onCreate(android.os.Bundle) 
* wird aufgerufen wenn android Activity anzeigen soll 
*/ 
@Override 
public void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.activity_project_view); 
datasource = new ProjectDatasource(this); 
showValuesFromDB(); 
} 
/* 
* Methode holt sich Projekte aus DB 
* und setzt vorhandene Values in die Liste 
*/ 
private void showValuesFromDB() { 
values.clear(); 
try { 
datasource.open(); 
values = datasource.getAllProjects(); 
datasource.close();
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
53 
} catch (Exception ex) { 
Toast.makeText(this, ex.toString(), Toast.LENGTH_LONG).show(); //Fehler ausgabe ToDo: Überschreiben mit eigenem Fehlertext 
} 
adapter = new ArrayAdapter<Project>(this, 
android.R.layout.simple_list_item_1, android.R.id.text1, values); 
// Assign adapter zur ListView 
ListView listView = (ListView) findViewById(R.id.listView1); 
listView.setAdapter(adapter); 
/* 
* Setze Onclicklistner auf die ListView um projekte auswählen zu könnnen. 
*/ 
listView.setOnItemClickListener(new OnItemClickListener() { 
public void onItemClick(AdapterView<?> parent, View view, 
int position, long id) { 
selectedItem = position; // the choosen one 
// change bgcolor of the selected item 
for (int a = 0; a < parent.getChildCount(); a++) { 
parent.getChildAt(a).setBackgroundColor(Color.WHITE); 
} 
view.setBackgroundColor(Color.GRAY); 
openOptionsMenu(); 
} 
}); 
} 
/* 
* (non-Javadoc) 
* @see android.app.Activity#onCreateOptionsMenu(android.view.Menu) 
* OptionsMenuStuff 
*/ 
@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
getMenuInflater().inflate(R.menu.activity_project_view, menu); 
return true; 
} 
@Override 
public boolean onOptionsItemSelected(MenuItem item) { 
if (item.getItemId() == R.id.addpj) { 
ListView listView = (ListView) findViewById(R.id.listView1); 
listView.setAdapter(adapter); 
// show the add view -> No Activity just a "Formular" Layout to switch into 
setContentView(R.layout.additem); 
} else if (item.getItemId() == R.id.removepj) { 
if (selectedItem != -999) { 
Project project = adapter.getItem(selectedItem); 
selectedItem = -999; 
try { 
datasource.open(); 
datasource.removeProject(project); 
datasource.close(); 
} catch (Exception ex) { 
Toast.makeText(this, ex.toString(), Toast.LENGTH_LONG) 
.show(); 
}
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
54 
// show the main view 
setContentView(R.layout.activity_project_view); 
showValuesFromDB(); 
} else { 
Toast.makeText(this, "Please choose a Item from List", 
Toast.LENGTH_LONG).show(); 
} 
} else if (item.getItemId() == R.id.showTodos) { 
//Intent nutzen um andere Activity zu starten und Werte zu übergen 
Intent i = new Intent(this, MyTodosOverview.class); 
Project project = adapter.getItem(selectedItem); 
i.putExtra("ProjectId", project.getId()); 
i.putExtra("ProjectName", project.getName()); 
startActivity(i); 
} else if (item.getItemId() == R.id.timemanager){ 
if (selectedItem != -999) { 
Intent i = new Intent(this, TimeManager.class); 
Project project = adapter.getItem(selectedItem); 
i.putExtra("ProjectId", project.getId()); 
i.putExtra("ProjectName", project.getName()); 
i.putExtra("workingtime", project.getTime()); 
startActivity(i); 
} else { 
Toast.makeText(this, "Please choose a Item from List", 
Toast.LENGTH_LONG).show(); 
} 
} 
return super.onOptionsItemSelected(item); 
} 
/* 
* Method of the Formular Layout additem.xml 
* Beschrieben im Layout als AddClick 
*/ 
public void AddClick(View view) { 
if (view.getId() == R.id.button1) { 
EditText text = (EditText) findViewById(R.id.editText1); 
// values.add(text.getText().toString()); 
// put the new value in the database 
try { 
datasource.open(); 
datasource.creatProject(text.getText().toString()); 
datasource.close(); 
} catch (Exception ex) { 
Toast.makeText(this, ex.toString(), Toast.LENGTH_LONG).show(); 
} 
// show the main view 
setContentView(R.layout.activity_project_view); 
showValuesFromDB(); 
} 
} 
}
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
55 
TimeManager.java 
package de.thorstenweiskopf.lpm; 
import java.text.SimpleDateFormat; 
import java.util.ArrayList; 
import java.util.Calendar; 
import java.util.Date; 
import java.util.List; 
import android.app.Activity; 
import android.app.DatePickerDialog; 
import android.app.TimePickerDialog; 
import android.app.DatePickerDialog.OnDateSetListener; 
import android.app.TimePickerDialog.OnTimeSetListener; 
import android.os.Bundle; 
import android.view.Menu; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.Button; 
import android.widget.DatePicker; 
import android.widget.TextView; 
import android.widget.TimePicker; 
import android.widget.Toast; 
import de.thorstenweiskopf.lpm.database.ProjectDatasource; 
import de.thorstenweiskopf.lpm.database.TimeTableDatasource; 
import de.thorstenweiskopf.lpm.dialogfragments.DatePickerFragment; 
import de.thorstenweiskopf.lpm.dialogfragments.TimePickerFragment; 
import de.thorstenweiskopf.lpm.model.TimeEntry; 
import de.thorstenweiskopf.lpm.R; 
import android.support.v4.app.FragmentActivity; 
//Fragmentactivity weil neu mit FragmentDialogen gearbeitet werdeb muss 
public class TimeManager extends FragmentActivity { 
//Buttons für Datum und Zeit 
private Button btnChangeTime, btnChangeDate; 
//Datum und Zeit Objekte 
//Kalender Objekt wird erzeugt und geändert vom Time und Datepicker bei Änderungen 
Calendar calendar = Calendar.getInstance(); 
final SimpleDateFormat date_format = new SimpleDateFormat("dd.MM.yyyy"); 
final SimpleDateFormat time_format = new SimpleDateFormat("HH:mm"); 
final SimpleDateFormat datetime_format = new SimpleDateFormat("dd.MM.yyyy HH:mm"); 
//Projektdaten 
private String projectname; 
private long projectid; 
private float workingtime_frompj; 
//DB Schnittstelle 
private TimeTableDatasource datasource; 
@Override 
public void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.activity_time_manager_view);
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
56 
//get the datasourceobject needed 
datasource = new TimeTableDatasource(this); 
setTimeOnView(calendar); 
setDateOnView(calendar); 
addTimeandDateButtonListners(); 
} 
/* 
* (non-Javadoc) 
* @see android.support.v4.app.FragmentActivity#onStart() 
* Wird die App hier in den Hintergrund gelegt bleibt aber aktiv 
* und kommt wieder in den Vordergrund so wird diese Methode ausgeführt 
* Sie holt sich das aktuelle Projekt und Zeigt die Zeit an da Diese Daten mitlerweile 
* nicht mehr in der View gespeichert sind. //onStart() in onResume() geändert 
*/ 
@Override 
protected void onResume() { 
super.onStart(); 
getProject(); 
showWorkingTime(); 
} 
/* 
* Hildmethode: Errechnet die Arbeitszeit des Projektes wenn möglich 
* und Schreibt sie in die Datenbank. In die ProjekteTabelle. 
* Wird nach jedem ein uns ausbuchen ausgeführt. 
*/ 
private boolean CalcWorkingTime(){ 
//Get the bookings, show 0 if no bookings are available 
List<TimeEntry> entrys = new ArrayList<TimeEntry>(); 
long worktime =0; 
try { 
datasource.open(); 
entrys = datasource.getAllTimeEntrysFromProject(String.valueOf(projectid)); 
} catch (Exception ex) { 
Toast.makeText(this, ex.toString(), Toast.LENGTH_LONG).show(); 
} 
if (entrys ==null | entrys.isEmpty()){ 
//Do NOTHING 
return false; 
} else { 
//Read the in and outs 
List <TimeEntry> in_entrys = new ArrayList<TimeEntry>(); 
List <TimeEntry> out_entrys = new ArrayList<TimeEntry>(); 
for (int i=0; i< entrys.size();i++ ){ 
if (entrys.get(i).getEntrytype() == 0){ 
in_entrys.add(entrys.get(i)); 
} else if (entrys.get(i).getEntrytype() == 1){ 
out_entrys.add(entrys.get(i)); 
} 
} 
//check if as many ins as outs 
if (in_entrys.size() == out_entrys.size()){ 
for (int i=0; i< in_entrys.size();i++ ){
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
57 
long checkout = out_entrys.get(i).getDatetime() ; 
long checkin = in_entrys.get(i).getDatetime(); 
worktime += (checkout-checkin )/1000/60; 
//Store in DB 
ProjectDatasource pd = new ProjectDatasource(this); 
pd.open(); 
pd.updateTime(projectid, worktime); 
pd.close(); 
} 
return true; 
} else { 
if (in_entrys.size() > out_entrys.size()){ 
TimeEntry lastTimeEntry = in_entrys.get(in_entrys.size()-1); 
long time = lastTimeEntry.getDatetime(); 
Calendar c = Calendar.getInstance(); 
c.setTimeInMillis(time); 
Toast.makeText(this, "Last checkin (" +datetime_format.format(c.getTime())+") without checkout.", Toast.LENGTH_LONG).show(); 
return false; 
} else { 
TimeEntry lastTimeEntry = out_entrys.get(out_entrys.size()- 1); 
long time = lastTimeEntry.getDatetime(); 
Calendar c = Calendar.getInstance(); 
c.setTimeInMillis(time); 
Toast.makeText(this, "Last checkout (" +datetime_format.format(c.getTime()) +") without checkin.", Toast.LENGTH_LONG).show(); 
return false; 
} 
} 
} 
} 
/* 
* Hilfmethode holt Arbeitszeit aus der ProjekteDB und zeigt sie an. 
*/ 
private void showWorkingTime() { 
String str_hours = "00"; 
String str_minutes = "00"; 
TextView tv = (TextView)findViewById(R.id.Text_ProjectTime); 
ProjectDatasource pd = new ProjectDatasource(this); 
pd.open(); 
workingtime_frompj = pd.getWorkingtime(projectid); 
pd.close(); 
int h = (int) workingtime_frompj/60; 
int minuten = (int)workingtime_frompj % 60; 
if (h < 10){ 
str_hours = "0"+h; 
} 
if (minuten < 10){ 
str_minutes = "0"+minuten; 
} 
tv.setText("Workingtime in hours: " +str_hours+":"+str_minutes); 
}
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
58 
/* 
* Hilfsmethode: Setzt die Listner auf alle Buttons 
* und führt jeweilige Hilfsfunktion aus 
*/ 
private void addTimeandDateButtonListners() { 
findViewById(R.id.button_date).setOnClickListener(new OnClickListener() { 
public void onClick(View v) { 
showDatePicker(); 
} 
}); 
findViewById(R.id.button_time).setOnClickListener(new OnClickListener() { 
public void onClick(View v) { 
showTimePicker(); 
} 
}); 
findViewById(R.id.button_checkin).setOnClickListener(new OnClickListener() { 
public void onClick(View v) { 
checkin(); 
} 
}); 
findViewById(R.id.button_checkout).setOnClickListener(new OnClickListener() { 
public void onClick(View v) { 
checkout(); 
} 
}); 
findViewById(R.id.button_hours).setOnClickListener(new OnClickListener() { 
public void onClick(View v) { 
justbookthetime(); 
} 
}); 
} 
/* 
* Hilfsmethode bucht eingestelle Zeit als Stunde und Minute 
* vom Calender Objetk 
*/ 
public void justbookthetime(){ 
int hour = calendar.get(Calendar.HOUR); 
int minutes = calendar.get(Calendar.MINUTE); 
int time = hour*60+minutes; 
//Store in DB 
ProjectDatasource pd = new ProjectDatasource(this); 
pd.open(); 
long wtime= pd.getWorkingtime(projectid); 
wtime = time +wtime; 
pd.updateTime(projectid, wtime); 
pd.close(); 
Toast.makeText(this, "timebooking done", Toast.LENGTH_LONG).show(); 
showWorkingTime(); 
} 
/* 
* Hilfsmethode mach Einträge in die TimeTable 
*/ 
public void checkin(){ 
long time = calendar.getTimeInMillis(); 
try {
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
59 
datasource.open(); 
datasource.creatTimeEntry(time, Long.toString(projectid),0);//0 for in 
datasource.close(); 
Toast.makeText(this, "checkin done", Toast.LENGTH_LONG).show(); 
boolean newWorkingTime = CalcWorkingTime(); 
if (newWorkingTime){ 
showWorkingTime(); 
} 
} catch (Exception ex){ 
Toast.makeText(this, ex.toString(), Toast.LENGTH_LONG) 
.show(); 
} 
} 
/* 
* Hilfsmethode macht Einträge in die TimeTable 
*/ 
public void checkout(){ 
long time = calendar.getTimeInMillis(); 
try { 
datasource.open(); 
datasource.creatTimeEntry(time, Long.toString(projectid),1);//1 for out 
datasource.close(); 
Toast.makeText(this, "checkout done", Toast.LENGTH_LONG).show(); 
boolean newWorkingTime = CalcWorkingTime(); 
if (newWorkingTime){ 
showWorkingTime(); 
} 
} catch (Exception ex){ 
Toast.makeText(this, ex.toString(), Toast.LENGTH_LONG) 
.show(); 
} 
} 
/* 
* Hilfmethode öffnet DatePicker mit aktuellem Datum 
*/ 
private void showDatePicker() { 
DatePickerFragment date = new DatePickerFragment(); 
/** 
* Set Up Current Date Into dialog 
*/ 
Calendar calender = Calendar.getInstance(); 
Bundle args = new Bundle(); 
args.putInt("year", calender.get(Calendar.YEAR)); 
args.putInt("month", calender.get(Calendar.MONTH)); 
args.putInt("day", calender.get(Calendar.DAY_OF_MONTH)); 
date.setArguments(args); 
/** 
* setze die RückkehrMethode wenn Datum ausgewählt wurde 
*/ 
date.setCallBack(ondate); 
date.show(getSupportFragmentManager(), "Date Picker"); 
} 
/* 
* Rückkehrmethode: Datum wurde ausgewählt vom Picker
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
60 
* setze Neue Daten im Calender und Zeige es an 
*/ 
public OnDateSetListener ondate = new OnDateSetListener() { 
public void onDateSet(DatePicker view, int year, int monthOfYear, 
int dayOfMonth) { 
calendar.set(year, monthOfYear, dayOfMonth); 
setDateOnView(calendar); 
} 
}; 
/* 
* Helpermethod opens Timepicker and set current time 
*/ 
private void showTimePicker() { 
TimePickerFragment timepicker = new TimePickerFragment(); 
/** 
* Set Up Current Date Into dialog 
*/ 
Calendar calender = Calendar.getInstance(); 
Bundle args = new Bundle(); 
args.putInt("minute", calender.get(Calendar.MINUTE)); 
args.putInt("hour", calender.get(Calendar.HOUR_OF_DAY)); 
timepicker.setArguments(args); 
/** 
* Set Call back to capture selected date 
*/ 
timepicker.setOnCallBack(ontime); 
timepicker.show(getSupportFragmentManager(), "Date Picker"); 
} 
/* 
* Helpermethod: Time was choosen from picker 
*/ 
public OnTimeSetListener ontime = new OnTimeSetListener() { 
public void onTimeSet(TimePicker view, int hour, int minute) { 
calendar.set(Calendar.HOUR_OF_DAY, hour); 
calendar.set(Calendar.MINUTE, minute); 
setTimeOnView(calendar); 
} 
}; 
/* 
* (non-Javadoc) 
* @see android.app.Activity#onCreateOptionsMenu(android.view.Menu) 
* OptionsMenuStuff: Gibt es hier nicht! 
*/ 
@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
//getMenuInflater().inflate(R.menu.activity_time_manager, menu); 
return true; 
} 
/* 
* Hilfsmethode holt sich vom Intent die Werte 
* und Erzeugt das Projekt und Zeigt den Namen in View an 
*/ 
public void getProject(){ 
//Lable anzeigen 
Bundle extras = getIntent().getExtras();
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
61 
if (extras == null) { 
return; 
} 
// Get data via the key 
projectname = extras.getString("ProjectName"); 
projectid = extras.getLong("ProjectId"); 
workingtime_frompj = extras.getLong("workingtime"); 
if (projectname != null) { 
// Show projectname as lable 
TextView lable = (TextView) findViewById(R.id.Text_ProjectLable); 
lable.setText(projectname); 
} 
} 
/* 
* Hilfsfunktion zeigt Zeit im Button 
*/ 
public void setTimeOnView(Calendar c){ 
Button time = (Button) findViewById(R.id.button_time); 
time.setText("Uhrzeit: "+time_format.format(c.getTime())); 
} 
/* 
* Hilfsfunktion zeigt Datum im Button 
*/ 
public void setDateOnView(Calendar c){ 
Button date = (Button) findViewById(R.id.button_date); 
date.setText("Datum: "+date_format.format(c.getTime())); 
} 
}
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
62 
MySQLiteHelper.java 
package de.thorstenweiskopf.lpm.database; 
import de.thorstenweiskopf.lpm.database.tables.ProjectTable; 
import de.thorstenweiskopf.lpm.database.tables.TimeTable; 
import de.thorstenweiskopf.lpm.database.tables.TodoTable; 
import android.annotation.TargetApi; 
import android.content.Context; 
import android.database.sqlite.SQLiteDatabase; 
import android.database.sqlite.SQLiteOpenHelper; 
@TargetApi(11) 
public class MySQLiteHelper extends SQLiteOpenHelper { 
private static final String DATABASE_NAME = "LittleProjectManager.db"; 
private static final int DATABASE_VERSION= 1; 
/* 
* Datenbank wird erstellt wenn 
* sie noch nicht existiert mit diesem Namen 
*/ 
@TargetApi(11) 
public MySQLiteHelper(Context context) { 
super(context, DATABASE_NAME, null, DATABASE_VERSION); 
} 
/* 
* (non-Javadoc) 
* @see android.database.sqlite.SQLiteOpenHelper#onCreate(android.database.sqlite.SQLiteDatabase) 
* Wird automatisch aufgerufen wenn DB noch nicht existiert 
* Es Werden alle benötigten Tabellen erstellt 
*/ 
@Override 
public void onCreate(SQLiteDatabase db) { 
ProjectTable.onCreate(db); 
TodoTable.onCreate(db); 
TimeTable.onCreate(db); 
} 
/* 
* (non-Javadoc) 
* @see android.database.sqlite.SQLiteOpenHelper#onUpgrade(android.database.sqlite.SQLiteDatabase, int, int) 
* wird ausgeführt wen DB Version sich im Code ändert 
*/ 
@Override 
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
TodoTable.onUpgrade(db, oldVersion, newVersion); 
} 
}
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
63 
ProjectDatasource.java 
/* 
* Klasse ist das DAO (Database Access Object) 
* Erlaubt den Zugriff auf die Datenbank und bietet Methoden 
* für das Abholen und Schreiben von Daten. 
*/ 
package de.thorstenweiskopf.lpm.database; 
import java.util.ArrayList; 
import java.util.List; 
import de.thorstenweiskopf.lpm.database.tables.ProjectTable; 
import de.thorstenweiskopf.lpm.database.tables.TodoTable; 
import de.thorstenweiskopf.lpm.model.Project; 
import de.thorstenweiskopf.lpm.model.ToDo; 
import android.content.ContentValues; 
import android.content.Context; 
import android.database.Cursor; 
import android.database.SQLException; 
import android.database.sqlite.SQLiteDatabase; 
public class ProjectDatasource { 
private SQLiteDatabase db; 
private MySQLiteHelper dbhelper; 
private String[] allCollums = {ProjectTable.COLUMN_ID, ProjectTable.COLUM_NAME, ProjectTable.COLUM_WORKTIME}; 
public ProjectDatasource(Context context) { 
dbhelper = new MySQLiteHelper(context); 
} 
/* 
* Öffnet DB Verbindung 
*/ 
public void open() throws SQLException { 
db = dbhelper.getWritableDatabase(); 
} 
/* 
* Schließt DB Verbindung 
*/ 
public void close() { 
db.close(); 
} 
/* 
* Erstellt Projekt in der Datenbank 
* @param name Projektname 
* @return Project 
*/ 
public Project creatProject(String name){ 
ContentValues values = new ContentValues();
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
64 
values.put(ProjectTable.COLUM_NAME, name); 
values.put(ProjectTable.COLUM_WORKTIME, 0); 
long insertId = db.insert(ProjectTable.TABLE_PJ, null, values); 
Cursor cursor = db.query(ProjectTable.TABLE_PJ, allCollums, TodoTable.COLUMN_ID+" = " +insertId, null, null, null, null); 
cursor.moveToFirst(); 
return makeProjectFromCursor(cursor); 
} 
/* 
* Entfernt Proket aus der Datenbank 
* @param pj Projekt welches entfernt werden soll 
*/ 
public void removeProject(Project pj){ 
long id = pj.getId(); 
System.out.println("Comment deleted with id: " + id); 
db.delete(ProjectTable.TABLE_PJ, ProjectTable.COLUMN_ID 
+ " = " + id, null); 
} 
/* 
* Gibt Liste aller Projekte zurück 
* @return ArrayList<Project> 
*/ 
public List<Project> getAllProjects(){ 
List<Project> projectlist = new ArrayList<Project>(); 
Cursor cursor = db.query(ProjectTable.TABLE_PJ, allCollums, null, null, null, null, null); 
cursor.moveToFirst(); 
if (cursor.getCount() == 0){ 
return projectlist; 
} 
while (cursor.isAfterLast() == false){ 
Project pj = makeProjectFromCursor(cursor); 
projectlist.add(pj); 
cursor.moveToNext(); 
} 
cursor.close(); 
return projectlist; 
} 
/* 
* Hilfmethode: Macht aus dem cursor(dbeintrag) ein neues Projekt 
* @param cursor: Db cursor 
* @return Project 
*/ 
private Project makeProjectFromCursor(Cursor cursor) { 
Project pj = new Project(); 
pj.setId(cursor.getLong(0));
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
65 
pj.setName(cursor.getString(1)); 
pj.setTime(cursor.getLong(2)); 
return pj; 
} 
/* 
* Trägt gesamte bisherige Arbeitszeit in die Tabelle ein 
* @param projectid: Id des Projektes 
* @param workingtime: arbeitszeit welche fürs Projekt in die DB soll 
*/ 
public void updateTime(long projectid, long workingtime) { 
ContentValues updateTime = new ContentValues(); 
updateTime.put(ProjectTable.COLUM_WORKTIME, Long.toString(workingtime)); 
db.update(ProjectTable.TABLE_PJ, updateTime, ProjectTable.COLUMN_ID+"=?", new String[] {Long.toString(projectid)}); 
} 
/* 
* Gibt die Arbeitszeit zurück 
* @param projectid: Id des Projektes 
* @return Arbeitszeit 
*/ 
public long getWorkingtime(long projectid) { 
Cursor cursor = db.query(ProjectTable.TABLE_PJ, new String[] {ProjectTable.COLUM_WORKTIME}, ProjectTable.COLUMN_ID+"=?", new String[]{Long.toString(projectid)}, null, null, null); 
cursor.moveToFirst(); 
return cursor.getLong(0); 
} 
}
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
66 
TimeTableDatasource.java 
/* 
* Klasse ist das DAO (Database Access Object) 
* Erlaubt den Zugriff auf die Datenbank und bietet Methoden 
* für das Abholen und Schreiben von Daten. 
*/ 
package de.thorstenweiskopf.lpm.database; 
import java.util.ArrayList; 
import java.util.List; 
import android.content.ContentValues; 
import android.content.Context; 
import android.database.Cursor; 
import android.database.SQLException; 
import android.database.sqlite.SQLiteDatabase; 
import de.thorstenweiskopf.lpm.database.tables.TimeTable; 
import de.thorstenweiskopf.lpm.model.TimeEntry; 
public class TimeTableDatasource { 
private SQLiteDatabase db; 
private MySQLiteHelper dbhelper; 
private String[] allCollums = {TimeTable.COLUMN_ID,TimeTable.COLUM_DATETIME, TimeTable.COLUM_PJ_ID, TimeTable.COLUM_ENTRYTYPE}; 
public TimeTableDatasource(Context context) { 
dbhelper = new MySQLiteHelper(context); 
} 
/* 
* Öffnet DB Verbindung 
*/ 
public void open() throws SQLException { 
db = dbhelper.getWritableDatabase(); 
} 
/* 
* Schließt DB Verbindung 
*/ 
public void close() { 
db.close(); 
} 
/* 
* Erstellt TimeEntry in der Datenbank 
* @param timeinms Zeit in Millisekunden 
* @param pjid Projektid des betreffenden Projektes 
* @param inOrOut 0 für einbuchen, 1 für ausbuchen 
* @return TimeEntry Objekt 
*/ 
public TimeEntry creatTimeEntry(long timeinms, String pjid, int inOrOut){ 
ContentValues values = new ContentValues(); 
values.put(TimeTable.COLUM_DATETIME, timeinms);
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
67 
values.put(TimeTable.COLUM_PJ_ID, pjid); 
values.put(TimeTable.COLUM_ENTRYTYPE, inOrOut); 
//in DB eintragen 
long insertId = db.insert(TimeTable.TABLE_TIMETABLE, null, values); 
//Eintrag holen 
Cursor cursor = db.query(TimeTable.TABLE_TIMETABLE, allCollums, TimeTable.COLUMN_ID+" = " +insertId, null, null, null, null); 
cursor.moveToFirst(); 
return makeTimeEntryFromCursor(cursor); 
} 
/* 
* Entfernt TimeEntry aus der Datenbank 
* @param te TimeEntry welches entfernt werden soll 
*/ 
public void removeTimeEntry(TimeEntry te){ 
long id = te.getId(); 
System.out.println("Comment deleted with id: " + id); 
db.delete(TimeTable.TABLE_TIMETABLE, TimeTable.COLUMN_ID 
+ " = " + id, null); 
} 
/* 
* Gibt Liste aller TimeEntry aus DB zurück 
* @return ArrayList<TimeEntry> 
*/ 
public List<TimeEntry> getAllTimeEntrys(){ 
List<TimeEntry> timeentrys = new ArrayList<TimeEntry>(); 
Cursor cursor = db.query(TimeTable.TABLE_TIMETABLE, allCollums, null, null, null, null, null); 
cursor.moveToFirst(); 
if (cursor.getCount() == 0){ 
return timeentrys; 
} 
while (cursor.isAfterLast() == false){ 
TimeEntry entry = makeTimeEntryFromCursor(cursor); 
timeentrys.add(entry); 
cursor.moveToNext(); 
} 
cursor.close(); 
return timeentrys; 
} 
/* 
* Hilfmethode: Macht aus dem cursor(dbeintrag) ein neues TimeEntry 
* @param cursor: Db cursor 
* @return TimeEntry 
*/ 
private TimeEntry makeTimeEntryFromCursor(Cursor cursor) { 
TimeEntry timeentry = new TimeEntry(); 
timeentry.setId(cursor.getLong(0)); 
timeentry.setDatetime(cursor.getLong(1));
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
68 
timeentry.setPj_id(cursor.getLong(2)); 
timeentry.setEntrytype(cursor.getLong(3)); 
return timeentry; 
} 
/* 
* Gibt Liste aller TimeEntry aus DB abhängig vom Projekt zurück 
* @param projectid 
* @return ArrayList<TimeEntry> 
*/ 
public List<TimeEntry> getAllTimeEntrysFromProject(String projectid) { 
List<TimeEntry> timeentrys = new ArrayList<TimeEntry>(); 
Cursor cursor = db.query(TimeTable.TABLE_TIMETABLE, allCollums, TimeTable.COLUM_PJ_ID +" = "+projectid, null, null, null, null); 
cursor.moveToFirst(); 
if (cursor.getCount() == 0){ 
return timeentrys; 
} 
while (cursor.isAfterLast() == false){ 
TimeEntry entry = makeTimeEntryFromCursor(cursor); 
timeentrys.add(entry); 
cursor.moveToNext(); 
} 
cursor.close(); 
return timeentrys; 
} 
}
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
69 
TodosDatasource.java 
package de.thorstenweiskopf.lpm.database; 
import java.util.ArrayList; 
import java.util.List; 
import de.thorstenweiskopf.lpm.database.tables.TodoTable; 
import de.thorstenweiskopf.lpm.model.ToDo; 
import android.content.ContentValues; 
import android.content.Context; 
import android.database.Cursor; 
import android.database.SQLException; 
import android.database.sqlite.SQLiteDatabase; 
public class TodosDatasource { 
private SQLiteDatabase db; 
private MySQLiteHelper dbhelper; 
private String[] allCollums = {TodoTable.COLUMN_ID,TodoTable.COLUM_TODO, TodoTable.COLUM_PJ_ID}; 
public TodosDatasource(Context context) { 
dbhelper = new MySQLiteHelper(context); 
} 
/* 
* Öffnet DB Verbindung 
*/ 
public void open() throws SQLException { 
db = dbhelper.getWritableDatabase(); 
} 
/* 
* Schließt DB Verbindung 
*/ 
public void close() { 
db.close(); 
} 
/* 
* Trägt ToDo in die Tabelle ein 
* @param projectid: Id des Projektes als Fremdschlüssel 
* @param todo: ToDo selbst als String 
* @return ToDo Objekt welches eingetragen wurde 
*/ 
public ToDo creatTodo(String todo, String pjid){ 
ContentValues values = new ContentValues(); 
values.put(TodoTable.COLUM_TODO, todo); 
values.put(TodoTable.COLUM_PJ_ID, pjid); 
//in DB eintragen 
long insertId = db.insert(TodoTable.TABLE_TODO, null, values); 
//Eintrag holen 
Cursor cursor = db.query(TodoTable.TABLE_TODO, allCollums, TodoTable.COLUMN_ID+" = " +insertId, null, null, null, null); 
cursor.moveToFirst();
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
70 
return makeTodoFromCursor(cursor); 
} 
/* 
* Entfernt ToDo aus der Datenbank 
* @param todo ToDo welches entfernt werden soll 
*/ 
public void removeTodo(ToDo todo){ 
long id = todo.getId(); 
System.out.println("Comment deleted with id: " + id); 
db.delete(TodoTable.TABLE_TODO, TodoTable.COLUMN_ID 
+ " = " + id, null); 
} 
/* 
* Gibt Liste aller ToDos zurück 
* @return ArrayList<ToDo> 
*/ 
public List<ToDo> getAllTodos(){ 
List<ToDo> todolist = new ArrayList<ToDo>(); 
Cursor cursor = db.query(TodoTable.TABLE_TODO, allCollums, null, null, null, null, null); 
cursor.moveToFirst(); 
if (cursor.getCount() == 0){ 
return todolist; 
} 
while (cursor.isAfterLast() == false){ 
ToDo todo = makeTodoFromCursor(cursor); 
todolist.add(todo); 
cursor.moveToNext(); 
} 
cursor.close(); 
return todolist; 
} 
/* 
* Hilfmethode: Macht aus dem cursor(dbeintrag) ein neues ToDo 
* @param cursor: Db cursor 
* @return ToDo 
*/ 
private ToDo makeTodoFromCursor(Cursor cursor) { 
ToDo todo = new ToDo(); 
todo.setId(cursor.getLong(0)); 
todo.setTodo(cursor.getString(1)); 
todo.setPj_id(cursor.getLong(2)); 
return todo; 
} 
/* 
* Gibt Liste aller ToDo aus DB abhängig vom Projekt zurück
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
71 
* @param projectid 
* @return ArrayList<ToDo> 
*/ 
public List<ToDo> getAllTodosFromProject(String projectid) { 
List<ToDo> todolist = new ArrayList<ToDo>(); 
Cursor cursor = db.query(TodoTable.TABLE_TODO, allCollums, TodoTable.COLUM_PJ_ID +" = "+projectid, null, null, null, null); 
cursor.moveToFirst(); 
if (cursor.getCount() == 0){ 
return todolist; 
} 
while (cursor.isAfterLast() == false){ 
ToDo todo = makeTodoFromCursor(cursor); 
todolist.add(todo); 
cursor.moveToNext(); 
} 
cursor.close(); 
return todolist; 
} 
}
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
72 
ProjectTable.java 
/* 
* Klasse stellt die Tabelle myprojects dar 
* in der Datenbank gespeichert wird 
*/ 
package de.thorstenweiskopf.lpm.database.tables; 
import de.thorstenweiskopf.lpm.database.MySQLiteHelper; 
import android.database.sqlite.SQLiteDatabase; 
import android.util.Log; 
public class ProjectTable { 
// Database table 
public static final String TABLE_PJ = "myprojects"; 
public static final String COLUMN_ID = "_id"; 
public static final String COLUM_NAME = "name"; 
public static final String COLUM_WORKTIME = "worktime"; 
//SQL CREATE Statement 
private static final String TABLE_CREATE_MYPROJECTS ="" 
+"create table " +TABLE_PJ +" ( " 
+COLUMN_ID+ " integer primary key autoincrement, " 
+COLUM_NAME +" text not null, " 
+COLUM_WORKTIME +" integer" 
+");"; 
/* 
* Tabelle erstellen 
*/ 
public static void onCreate(SQLiteDatabase db) { 
db.execSQL(TABLE_CREATE_MYPROJECTS); 
} 
/* 
* Tabelle Upgraden 
*/ 
public static void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
Log.w(MySQLiteHelper.class.getName(), 
"Upgrading database from version " + oldVersion + " to " 
+ newVersion + ", which will destroy all old data"); 
db.execSQL("DROP TABLE IF EXISTS " + TABLE_PJ); 
onCreate(db); 
} 
}
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
73 
TimeTable.java 
/* 
* Klasse stellt die Tabelle timetable dar 
* in der Datenbank gespeichert wird 
*/ 
package de.thorstenweiskopf.lpm.database.tables; 
import android.database.sqlite.SQLiteDatabase; 
import android.util.Log; 
import de.thorstenweiskopf.lpm.database.MySQLiteHelper; 
public class TimeTable { 
// Database table 
public static final String TABLE_TIMETABLE = "timetable"; 
public static final String COLUMN_ID = "_id"; 
public static final String COLUM_DATETIME = "datetime"; 
public static final String COLUM_PJ_ID = "pj_id"; 
public static final String COLUM_ENTRYTYPE = "entrytype"; 
//SQL CREATE Statement 
private static final String TABLE_CREATE_TIMETABLE ="" 
+"create table " +TABLE_TIMETABLE +" ( " 
+COLUMN_ID+ " integer primary key autoincrement, " 
+COLUM_DATETIME +" integer not null, " 
+COLUM_PJ_ID + " integer, " 
+COLUM_ENTRYTYPE + " integer not null," 
+ " FOREIGN KEY ("+COLUM_PJ_ID+") REFERENCES "+ProjectTable.TABLE_PJ+" ("+ProjectTable.COLUMN_ID+")" 
+");"; 
/* 
* Tabelle erstellen 
*/ 
public static void onCreate(SQLiteDatabase db) { 
db.execSQL(TABLE_CREATE_TIMETABLE); 
} 
/* 
* Tabelle Upgraden 
*/ 
public static void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
Log.w(MySQLiteHelper.class.getName(), 
"Upgrading database from version " + oldVersion + " to " 
+ newVersion + ", which will destroy all old data"); 
db.execSQL("DROP TABLE IF EXISTS " + TABLE_TIMETABLE); 
onCreate(db); 
} 
}
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
74 
TodoTable.java 
/* 
* Klasse stellt die Tabelle mytodos dar 
* in der Datenbank gespeichert wird 
*/ 
package de.thorstenweiskopf.lpm.database.tables; 
import de.thorstenweiskopf.lpm.database.MySQLiteHelper; 
import android.annotation.TargetApi; 
import android.content.Context; 
import android.database.sqlite.SQLiteDatabase; 
import android.util.Log; 
public class TodoTable { 
// Database table 
public static final String TABLE_TODO = "mytodos"; 
public static final String COLUMN_ID = "_id"; 
public static final String COLUM_TODO = "todo"; 
public static final String COLUM_PJ_ID = "pj_id"; 
//SQL CREATE Statement 
private static final String TABLE_CREATE_MYTODOS ="" 
+"create table " +TABLE_TODO +" ( " 
+COLUMN_ID+ " integer primary key autoincrement, " 
+COLUM_TODO +" text not null, " 
+COLUM_PJ_ID + " integer," 
+ " FOREIGN KEY ("+COLUM_PJ_ID+") REFERENCES "+ProjectTable.TABLE_PJ+" ("+ProjectTable.COLUMN_ID+")" 
+");"; 
/* 
* Tabelle erstellen 
*/ 
public static void onCreate(SQLiteDatabase db) { 
db.execSQL(TABLE_CREATE_MYTODOS); 
} 
/* 
* Tabelle Upgraden 
*/ 
public static void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
Log.w(MySQLiteHelper.class.getName(), 
"Upgrading database from version " + oldVersion + " to " 
+ newVersion + ", which will destroy all old data"); 
db.execSQL("DROP TABLE IF EXISTS " + TABLE_TODO); 
onCreate(db); 
} 
}
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
75 
DatePickerFragment.java 
/* 
* Klasse muss als sogenantes DatePickerFragment geschrieben werden 
* welche Ihrerseits bei der Erzeugung einen DatePickerDialog öffnet 
* Den Rest übernimmt dann Das Framework bzw. die Activity welches 
* diese Klasse mit Argumenten füttert und Ausführen lässt 
*/ 
package de.thorstenweiskopf.lpm.dialogfragments; 
import android.app.DatePickerDialog; 
import android.app.DatePickerDialog.OnDateSetListener; 
import android.app.Dialog; 
import android.os.Bundle; 
import android.support.v4.app.DialogFragment; 
public class DatePickerFragment extends DialogFragment { 
//Klassenvariablen 
private int year, month, day; 
OnDateSetListener ondateSet; 
public DatePickerFragment() { 
} 
public void setCallBack(OnDateSetListener ondate) { 
ondateSet = ondate; 
} 
/* 
* (non-Javadoc) 
* 
* @see android.support.v4.app.Fragment#setArguments(android.os.Bundle) 
* Methode um Daten zu setzen 
*/ 
@Override 
public void setArguments(Bundle args) { 
super.setArguments(args); 
year = args.getInt("year"); 
month = args.getInt("month"); 
day = args.getInt("day"); 
} 
@Override 
public Dialog onCreateDialog(Bundle savedInstanceState) { 
return new DatePickerDialog(getActivity(), ondateSet, year, month, day); 
} 
}
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
76 
TimePickerFragment.java 
/* 
* Klasse muss als sogenantes TimePickerFragement geschrieben werden 
* welche Ihrerseits bei der Erzeugung einen TimePickerDialog öffnet 
* Den Rest übernimmt dann Das Framework bzw. die Activity welches 
* diese Klasse mit Argumenten füttert und Ausführen lässt 
*/ 
package de.thorstenweiskopf.lpm.dialogfragments; 
import android.app.Dialog; 
import android.app.TimePickerDialog; 
import android.app.TimePickerDialog.OnTimeSetListener; 
import android.os.Bundle; 
import android.support.v4.app.DialogFragment; 
public class TimePickerFragment extends DialogFragment { 
//Klassen variablen 
private int hour, minute; 
OnTimeSetListener ontimeset; 
public TimePickerFragment() { 
} 
public void setOnCallBack (OnTimeSetListener ontime){ 
ontimeset = ontime; 
} 
/* 
* (non-Javadoc) 
* @see android.support.v4.app.Fragment#setArguments(android.os.Bundle) 
* Methode um Daten zu setzen 
*/ 
@Override 
public void setArguments(Bundle args) { 
super.setArguments(args); 
hour = args.getInt("hour"); 
minute = args.getInt("minute"); 
} 
@Override 
public Dialog onCreateDialog(Bundle savedInstanceState) { 
return new TimePickerDialog(getActivity(), ontimeset, hour, minute, true); 
} 
}
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
77 
TimeEntry.java 
/* 
* Klasse stellt ein TimeEntry dar wie es 
* in der Datenbank gespeichert wird 
*/ 
package de.thorstenweiskopf.lpm.model; 
public class TimeEntry { 
private long datetime; 
private int entrytype; //0 in 1 out 
private long id; 
private long pj_id; 
public long getDatetime() { 
return datetime; 
} 
public void setDatetime(long datetime) { 
this.datetime = datetime; 
} 
public int getEntrytype() { 
return entrytype; 
} 
public void setEntrytype(long entrytype) { 
this.entrytype = (int) entrytype; 
} 
public long getId() { 
return id; 
} 
public void setId(long id) { 
this.id = id; 
} 
public long getPj_id() { 
return pj_id; 
} 
public void setPj_id(long pj_id) { 
this.pj_id = pj_id; 
} 
}
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
78 
ToDo.java 
/* 
* Klasse stellt ein ToDo dar wie es 
* in der Datenbank gespeichert wird 
*/ 
package de.thorstenweiskopf.lpm.model; 
public class ToDo { 
private String todo; 
private long id; 
private long pj_id; 
public String getTodo() { 
return todo; 
} 
public void setTodo(String todo) { 
this.todo = todo; 
} 
public long getId() { 
return id; 
} 
public void setId(long id) { 
this.id = id; 
} 
public long getPj_id() { 
return pj_id; 
} 
public void setPj_id(long pj_id) { 
this.pj_id = pj_id; 
} 
//Rückgabewert des Objektes für die Liste 
public String toString(){ 
return todo; 
} 
}
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
79 
R.java 
/* AUTO-GENERATED FILE. DO NOT MODIFY. 
* 
* This class was automatically generated by the 
* aapt tool from the resource data it found. It 
* should not be modified by hand. 
*/ 
package de.thorstenweiskopf.lpm; 
public final class R { 
public static final class attr { 
} 
public static final class drawable { 
public static final int ic_action_search=0x7f020000; 
public static final int ic_launcher=0x7f020001; 
} 
public static final class id { 
public static final int Add=0x7f07000f; 
public static final int Remove=0x7f070010; 
public static final int Text_ProjectLable=0x7f070001; 
public static final int Text_ProjectTime=0x7f070002; 
public static final int addpj=0x7f07000b; 
public static final int button1=0x7f07000a; 
public static final int button_checkin=0x7f070005; 
public static final int button_checkout=0x7f070006; 
public static final int button_date=0x7f070003; 
public static final int button_hours=0x7f070007; 
public static final int button_time=0x7f070004; 
public static final int editText1=0x7f070009; 
public static final int listView1=0x7f070000; 
public static final int removepj=0x7f07000d; 
public static final int showTodos=0x7f07000c; 
public static final int timemanager=0x7f07000e; 
public static final int todo_lable=0x7f070008; 
} 
public static final class layout { 
public static final int activity_project_view=0x7f030000; 
public static final int activity_time_manager_view=0x7f030001; 
public static final int activity_todos_view=0x7f030002; 
public static final int additem=0x7f030003; 
} 
public static final class menu { 
public static final int activity_project_view=0x7f060000; 
public static final int activity_todos_view=0x7f060001; 
} 
public static final class string { 
public static final int Add=0x7f040002; 
public static final int Remove=0x7f040003; 
public static final int app_name=0x7f040000; 
public static final int menu_addpj=0x7f040008; 
public static final int menu_remove_pj=0x7f04000a; 
public static final int menu_settings=0x7f040007; 
public static final int menu_showtodos=0x7f040009; 
public static final int menu_timemanager=0x7f04000b; 
public static final int menu_timestats=0x7f04000c; 
public static final int time_checkinbutton=0x7f04000d; 
public static final int time_checkoutbutton=0x7f04000e;
10. Januar 
2013 
APPLIKATIONSENTWICKLUNG FÜR ANDROID 
80 
public static final int time_hourbutton=0x7f04000f; 
public static final int title_activity_my_todo_add=0x7f040004; 
public static final int title_activity_my_todos_overview=0x7f040001; 
public static final int title_activity_project_view=0x7f040005; 
public static final int title_activity_time_manager=0x7f040006; 
} 
public static final class style { 
public static final int AppTheme=0x7f050000; 
} 
}

Weitere ähnliche Inhalte

Andere mochten auch

Musculatura de las extremidades
Musculatura de las extremidadesMusculatura de las extremidades
Musculatura de las extremidadesBlanca
 
Congreso Educativo INACAP 2014 - Jessica Püschell, Claudia Yañez
Congreso Educativo INACAP 2014 - Jessica Püschell, Claudia YañezCongreso Educativo INACAP 2014 - Jessica Püschell, Claudia Yañez
Congreso Educativo INACAP 2014 - Jessica Püschell, Claudia YañezINACAP
 
Congreso Educativo INACAP 2014 - Susana Gomes-Lourenco
Congreso Educativo INACAP 2014 - Susana Gomes-LourencoCongreso Educativo INACAP 2014 - Susana Gomes-Lourenco
Congreso Educativo INACAP 2014 - Susana Gomes-LourencoINACAP
 
Arbeitsplatz der Zukunft - We4IT Collaboration Cloud
Arbeitsplatz der Zukunft - We4IT Collaboration CloudArbeitsplatz der Zukunft - We4IT Collaboration Cloud
Arbeitsplatz der Zukunft - We4IT Collaboration CloudWe4IT Group
 
Bildimplikatur
BildimplikaturBildimplikatur
BildimplikaturPictonkiwi
 
Foodfunding mit Erzeugerwelt.de
Foodfunding mit Erzeugerwelt.deFoodfunding mit Erzeugerwelt.de
Foodfunding mit Erzeugerwelt.deJohannes Tschesche
 
Congreso Educativo INACAP 2014 - Jorge Contreras, Mario Zapata
Congreso Educativo INACAP 2014 - Jorge Contreras, Mario ZapataCongreso Educativo INACAP 2014 - Jorge Contreras, Mario Zapata
Congreso Educativo INACAP 2014 - Jorge Contreras, Mario ZapataINACAP
 
Dieter's weinfunatiker magazin
Dieter's weinfunatiker magazinDieter's weinfunatiker magazin
Dieter's weinfunatiker magazinDieter Freiermuth
 
Blu-ray, DVD- und CD-Neuheiten Oktober 2013 Nr. 2 (Im Vertrieb der NAXOS Deut...
Blu-ray, DVD- und CD-Neuheiten Oktober 2013 Nr. 2 (Im Vertrieb der NAXOS Deut...Blu-ray, DVD- und CD-Neuheiten Oktober 2013 Nr. 2 (Im Vertrieb der NAXOS Deut...
Blu-ray, DVD- und CD-Neuheiten Oktober 2013 Nr. 2 (Im Vertrieb der NAXOS Deut...NAXOS Deutschland GmbH
 

Andere mochten auch (20)

Modalidades de Prácticas
Modalidades de PrácticasModalidades de Prácticas
Modalidades de Prácticas
 
FOM Steuerrecht: Steuerliches Vollstreckungsverfahren
FOM Steuerrecht: Steuerliches VollstreckungsverfahrenFOM Steuerrecht: Steuerliches Vollstreckungsverfahren
FOM Steuerrecht: Steuerliches Vollstreckungsverfahren
 
Binder3
Binder3Binder3
Binder3
 
Musculatura de las extremidades
Musculatura de las extremidadesMusculatura de las extremidades
Musculatura de las extremidades
 
3DUVIS - EN
3DUVIS - EN3DUVIS - EN
3DUVIS - EN
 
Auto cad comandos
Auto cad comandosAuto cad comandos
Auto cad comandos
 
Perifã©ricos de salida
Perifã©ricos de salidaPerifã©ricos de salida
Perifã©ricos de salida
 
Congreso Educativo INACAP 2014 - Jessica Püschell, Claudia Yañez
Congreso Educativo INACAP 2014 - Jessica Püschell, Claudia YañezCongreso Educativo INACAP 2014 - Jessica Püschell, Claudia Yañez
Congreso Educativo INACAP 2014 - Jessica Püschell, Claudia Yañez
 
FOM Mediation: Beispiel, Der Scheidungs-Fall Becker
FOM Mediation: Beispiel, Der Scheidungs-Fall BeckerFOM Mediation: Beispiel, Der Scheidungs-Fall Becker
FOM Mediation: Beispiel, Der Scheidungs-Fall Becker
 
Congreso Educativo INACAP 2014 - Susana Gomes-Lourenco
Congreso Educativo INACAP 2014 - Susana Gomes-LourencoCongreso Educativo INACAP 2014 - Susana Gomes-Lourenco
Congreso Educativo INACAP 2014 - Susana Gomes-Lourenco
 
Arbeitsplatz der Zukunft - We4IT Collaboration Cloud
Arbeitsplatz der Zukunft - We4IT Collaboration CloudArbeitsplatz der Zukunft - We4IT Collaboration Cloud
Arbeitsplatz der Zukunft - We4IT Collaboration Cloud
 
Bildimplikatur
BildimplikaturBildimplikatur
Bildimplikatur
 
Amazon berries
Amazon berriesAmazon berries
Amazon berries
 
HB SG
HB SGHB SG
HB SG
 
Plan de apoyo
Plan de apoyo Plan de apoyo
Plan de apoyo
 
Foodfunding mit Erzeugerwelt.de
Foodfunding mit Erzeugerwelt.deFoodfunding mit Erzeugerwelt.de
Foodfunding mit Erzeugerwelt.de
 
Pag 23
Pag 23Pag 23
Pag 23
 
Congreso Educativo INACAP 2014 - Jorge Contreras, Mario Zapata
Congreso Educativo INACAP 2014 - Jorge Contreras, Mario ZapataCongreso Educativo INACAP 2014 - Jorge Contreras, Mario Zapata
Congreso Educativo INACAP 2014 - Jorge Contreras, Mario Zapata
 
Dieter's weinfunatiker magazin
Dieter's weinfunatiker magazinDieter's weinfunatiker magazin
Dieter's weinfunatiker magazin
 
Blu-ray, DVD- und CD-Neuheiten Oktober 2013 Nr. 2 (Im Vertrieb der NAXOS Deut...
Blu-ray, DVD- und CD-Neuheiten Oktober 2013 Nr. 2 (Im Vertrieb der NAXOS Deut...Blu-ray, DVD- und CD-Neuheiten Oktober 2013 Nr. 2 (Im Vertrieb der NAXOS Deut...
Blu-ray, DVD- und CD-Neuheiten Oktober 2013 Nr. 2 (Im Vertrieb der NAXOS Deut...
 

Ähnlich wie Einführung in die Android Applikationsentwicklung

Smartphone Betriebssysteme Android
Smartphone Betriebssysteme AndroidSmartphone Betriebssysteme Android
Smartphone Betriebssysteme Androiddm-development
 
Smartphone Betriebssysteme iOS
Smartphone Betriebssysteme iOSSmartphone Betriebssysteme iOS
Smartphone Betriebssysteme iOSdm-development
 
01-2015 - Java aktuell - Mandy Goram - Entwicklung mobiler Anwendungen für Bl...
01-2015 - Java aktuell - Mandy Goram - Entwicklung mobiler Anwendungen für Bl...01-2015 - Java aktuell - Mandy Goram - Entwicklung mobiler Anwendungen für Bl...
01-2015 - Java aktuell - Mandy Goram - Entwicklung mobiler Anwendungen für Bl...Mandy Goram
 
Smartphone Betriebssysteme Windows Phone
Smartphone Betriebssysteme Windows PhoneSmartphone Betriebssysteme Windows Phone
Smartphone Betriebssysteme Windows Phonedm-development
 
Watchkit - Programmieren für die Apple Watch
Watchkit - Programmieren für die Apple WatchWatchkit - Programmieren für die Apple Watch
Watchkit - Programmieren für die Apple Watchdirkkoller
 
Mobile Anwendungen mit Apache Cordova
Mobile Anwendungen mit Apache CordovaMobile Anwendungen mit Apache Cordova
Mobile Anwendungen mit Apache CordovaYvette Teiken
 
Das Android Open Source Project
Das Android Open Source ProjectDas Android Open Source Project
Das Android Open Source Projectinovex GmbH
 
CSI: WP - Dem Windows Phone auf der Spur, Internetspecial: SDK & Development-...
CSI: WP - Dem Windows Phone auf der Spur, Internetspecial: SDK & Development-...CSI: WP - Dem Windows Phone auf der Spur, Internetspecial: SDK & Development-...
CSI: WP - Dem Windows Phone auf der Spur, Internetspecial: SDK & Development-...Gordon Breuer
 
Cross Plattform Entwicklung für Mobile Anwendungen
Cross Plattform Entwicklung für Mobile AnwendungenCross Plattform Entwicklung für Mobile Anwendungen
Cross Plattform Entwicklung für Mobile AnwendungenMarkus Eiglsperger
 
Smartphone Betriebssysteme BlackBerry
Smartphone Betriebssysteme BlackBerrySmartphone Betriebssysteme BlackBerry
Smartphone Betriebssysteme BlackBerrydm-development
 
iOS Apps mit Webtechnologien erstellen
iOS Apps mit Webtechnologien erstelleniOS Apps mit Webtechnologien erstellen
iOS Apps mit Webtechnologien erstellenMichael Kühnel
 
Android Apps mit Xamarin entwickeln
Android Apps mit Xamarin entwickelnAndroid Apps mit Xamarin entwickeln
Android Apps mit Xamarin entwickelnAndré Krämer
 
DWX 2017 - Alternativen zu Visual-Studio-Testtools: Wann lohnt es sich auch m...
DWX 2017 - Alternativen zu Visual-Studio-Testtools: Wann lohnt es sich auch m...DWX 2017 - Alternativen zu Visual-Studio-Testtools: Wann lohnt es sich auch m...
DWX 2017 - Alternativen zu Visual-Studio-Testtools: Wann lohnt es sich auch m...Marc Müller
 
Slides zum Impulsreferat: HCL UDP - DNUG Stammtisch Salzburg
Slides zum Impulsreferat: HCL UDP - DNUG Stammtisch SalzburgSlides zum Impulsreferat: HCL UDP - DNUG Stammtisch Salzburg
Slides zum Impulsreferat: HCL UDP - DNUG Stammtisch SalzburgDNUG e.V.
 
Code-Generierung vereinfacht IoT-Entwicklung
Code-Generierung vereinfacht IoT-EntwicklungCode-Generierung vereinfacht IoT-Entwicklung
Code-Generierung vereinfacht IoT-Entwicklungbhoeck
 
Android Entwicklung GTUG München 2009
Android Entwicklung GTUG München 2009Android Entwicklung GTUG München 2009
Android Entwicklung GTUG München 2009greenrobot
 
SharePoint, HTML5 und mobile Geräte (SharePoint UserGroup Dresden 11/2011)
SharePoint, HTML5 und mobile Geräte (SharePoint UserGroup Dresden 11/2011)SharePoint, HTML5 und mobile Geräte (SharePoint UserGroup Dresden 11/2011)
SharePoint, HTML5 und mobile Geräte (SharePoint UserGroup Dresden 11/2011)Christian Heindel
 

Ähnlich wie Einführung in die Android Applikationsentwicklung (20)

Smartphone Betriebssysteme Android
Smartphone Betriebssysteme AndroidSmartphone Betriebssysteme Android
Smartphone Betriebssysteme Android
 
Smartphone Betriebssysteme iOS
Smartphone Betriebssysteme iOSSmartphone Betriebssysteme iOS
Smartphone Betriebssysteme iOS
 
01-2015 - Java aktuell - Mandy Goram - Entwicklung mobiler Anwendungen für Bl...
01-2015 - Java aktuell - Mandy Goram - Entwicklung mobiler Anwendungen für Bl...01-2015 - Java aktuell - Mandy Goram - Entwicklung mobiler Anwendungen für Bl...
01-2015 - Java aktuell - Mandy Goram - Entwicklung mobiler Anwendungen für Bl...
 
Smartphone Betriebssysteme Windows Phone
Smartphone Betriebssysteme Windows PhoneSmartphone Betriebssysteme Windows Phone
Smartphone Betriebssysteme Windows Phone
 
Watchkit - Programmieren für die Apple Watch
Watchkit - Programmieren für die Apple WatchWatchkit - Programmieren für die Apple Watch
Watchkit - Programmieren für die Apple Watch
 
Mobile Anwendungen mit Apache Cordova
Mobile Anwendungen mit Apache CordovaMobile Anwendungen mit Apache Cordova
Mobile Anwendungen mit Apache Cordova
 
Das Android Open Source Project
Das Android Open Source ProjectDas Android Open Source Project
Das Android Open Source Project
 
CSI: WP - Dem Windows Phone auf der Spur, Internetspecial: SDK & Development-...
CSI: WP - Dem Windows Phone auf der Spur, Internetspecial: SDK & Development-...CSI: WP - Dem Windows Phone auf der Spur, Internetspecial: SDK & Development-...
CSI: WP - Dem Windows Phone auf der Spur, Internetspecial: SDK & Development-...
 
Cross Plattform Entwicklung für Mobile Anwendungen
Cross Plattform Entwicklung für Mobile AnwendungenCross Plattform Entwicklung für Mobile Anwendungen
Cross Plattform Entwicklung für Mobile Anwendungen
 
Smartphone Betriebssysteme BlackBerry
Smartphone Betriebssysteme BlackBerrySmartphone Betriebssysteme BlackBerry
Smartphone Betriebssysteme BlackBerry
 
Android doc
Android docAndroid doc
Android doc
 
iOS Apps mit Webtechnologien erstellen
iOS Apps mit Webtechnologien erstelleniOS Apps mit Webtechnologien erstellen
iOS Apps mit Webtechnologien erstellen
 
Android Apps mit Xamarin entwickeln
Android Apps mit Xamarin entwickelnAndroid Apps mit Xamarin entwickeln
Android Apps mit Xamarin entwickeln
 
DWX 2017 - Alternativen zu Visual-Studio-Testtools: Wann lohnt es sich auch m...
DWX 2017 - Alternativen zu Visual-Studio-Testtools: Wann lohnt es sich auch m...DWX 2017 - Alternativen zu Visual-Studio-Testtools: Wann lohnt es sich auch m...
DWX 2017 - Alternativen zu Visual-Studio-Testtools: Wann lohnt es sich auch m...
 
Slides zum Impulsreferat: HCL UDP - DNUG Stammtisch Salzburg
Slides zum Impulsreferat: HCL UDP - DNUG Stammtisch SalzburgSlides zum Impulsreferat: HCL UDP - DNUG Stammtisch Salzburg
Slides zum Impulsreferat: HCL UDP - DNUG Stammtisch Salzburg
 
Code-Generierung vereinfacht IoT-Entwicklung
Code-Generierung vereinfacht IoT-EntwicklungCode-Generierung vereinfacht IoT-Entwicklung
Code-Generierung vereinfacht IoT-Entwicklung
 
Android Entwicklung GTUG München 2009
Android Entwicklung GTUG München 2009Android Entwicklung GTUG München 2009
Android Entwicklung GTUG München 2009
 
SharePoint, HTML5 und mobile Geräte (SharePoint UserGroup Dresden 11/2011)
SharePoint, HTML5 und mobile Geräte (SharePoint UserGroup Dresden 11/2011)SharePoint, HTML5 und mobile Geräte (SharePoint UserGroup Dresden 11/2011)
SharePoint, HTML5 und mobile Geräte (SharePoint UserGroup Dresden 11/2011)
 
Mobile Applikationen: Entwicklung, Rollout, Wartung - Tipps und Tricks für di...
Mobile Applikationen: Entwicklung, Rollout, Wartung - Tipps und Tricks für di...Mobile Applikationen: Entwicklung, Rollout, Wartung - Tipps und Tricks für di...
Mobile Applikationen: Entwicklung, Rollout, Wartung - Tipps und Tricks für di...
 
Test-Automation mit Selenium WebDriver - ein Artikel der iks im dotnetpro
Test-Automation mit Selenium WebDriver - ein Artikel der iks im dotnetproTest-Automation mit Selenium WebDriver - ein Artikel der iks im dotnetpro
Test-Automation mit Selenium WebDriver - ein Artikel der iks im dotnetpro
 

Mehr von Thorsten Weiskopf

Volierenbau mit IKEA Ivar Regal
Volierenbau mit IKEA Ivar RegalVolierenbau mit IKEA Ivar Regal
Volierenbau mit IKEA Ivar RegalThorsten Weiskopf
 
Balance Score Card Kurz und Knapp
Balance Score Card Kurz und KnappBalance Score Card Kurz und Knapp
Balance Score Card Kurz und KnappThorsten Weiskopf
 
Farbgestaltung & Typographie bei Webseiten
Farbgestaltung & Typographie bei WebseitenFarbgestaltung & Typographie bei Webseiten
Farbgestaltung & Typographie bei WebseitenThorsten Weiskopf
 
Was ist der Verzeichnisdienst X500
Was ist der Verzeichnisdienst X500 Was ist der Verzeichnisdienst X500
Was ist der Verzeichnisdienst X500 Thorsten Weiskopf
 

Mehr von Thorsten Weiskopf (6)

Volierenbau mit IKEA Ivar Regal
Volierenbau mit IKEA Ivar RegalVolierenbau mit IKEA Ivar Regal
Volierenbau mit IKEA Ivar Regal
 
Balance Score Card Kurz und Knapp
Balance Score Card Kurz und KnappBalance Score Card Kurz und Knapp
Balance Score Card Kurz und Knapp
 
Social media & business
Social media & businessSocial media & business
Social media & business
 
Unix Dateisysteme
Unix DateisystemeUnix Dateisysteme
Unix Dateisysteme
 
Farbgestaltung & Typographie bei Webseiten
Farbgestaltung & Typographie bei WebseitenFarbgestaltung & Typographie bei Webseiten
Farbgestaltung & Typographie bei Webseiten
 
Was ist der Verzeichnisdienst X500
Was ist der Verzeichnisdienst X500 Was ist der Verzeichnisdienst X500
Was ist der Verzeichnisdienst X500
 

Einführung in die Android Applikationsentwicklung

  • 1. FSIV10 THORSTEN WEISKOPF APPLIKATIONSENTWICKLUNG FÜR ANDROID
  • 2. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 2 1 Einführung ................................................................................................... 3 2 Kapitel 1 – Android Grundlagen ................................................................... 4 2.1 Was ist Android? ........................................................................................................... 4 2.2 Die Entwicklungsumgebung .......................................................................................... 4 2.3 Google ADT.................................................................................................................... 5 2.4 Grober Aufbau einer Android App ................................................................................ 8 2.5 Grundlagen der Android Entwicklung ......................................................................... 10 2.5.1 View-Activity-Event-Intent .................................................................................. 10 2.5.2 Activity Lebenszyklus........................................................................................... 12 2.5.3 Die wichtigsten XML Dateien ausserhalb der Layouts ........................................ 14 2.5.4 Persistenz und Datenspeicherung in Adnroid ..................................................... 15 3 Kapitel 2 - App Dokumentation LittleProjectManager ................................ 16 3.1 Beschreibung der Applikation ..................................................................................... 16 3.2 Architektur und Funktionsweise der Applikation ....................................................... 18 3.2.1 Activity-View und Layout (VIEW) ........................................................................ 18 3.2.2 Activitys (Controller) ........................................................................................... 20 3.2.3 Dialogfragmente (Controller) .............................................................................. 23 3.2.4 Plain-Old-Java-Objects (Model) .......................................................................... 24 3.2.5 DataAccessObjects (Model) ................................................................................ 24 3.2.6 MySQLiteHelper und seine Tabellenklassen (Model) ......................................... 25 3.3 SQLite Datenbank ........................................................................................................ 26 3.3.1 Datenbankstruktur .............................................................................................. 27 3.4 Projekt und Paketstruktur ........................................................................................... 29 3.4.1 Pakete und Klassen ............................................................................................. 29 3.4.2 Projektdateien und Ressourcen .......................................................................... 31 4 Ausblick und Fazit ..................................................................................... 33 5 Abbildungsverzeichnis ............................................................................... 34 6 Abkürzungsverzeichnis .............................................................................. 35 7 Anlagen ..................................................................................................... 36 7.1 Eclipse Workbench ...................................................................................................... 37 7.2 Screenshots LittleProjectManager .............................................................................. 38 7.3 Architekturschaubild ................................................................................................... 40 7.4 Quellcode der Applikation .......................................................................................... 41
  • 3. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 3 1 Einführung Dieses Dokument entstand im Rahmen einer abschließenden Leistungsfeststellung des Modules Softwareentwicklung. Vorgabe war es das Gebiet der Android Applikationsentwicklung zu erschließen und eine für den Bereich typische Applikation zu realisieren. Das Dokument gliedert sich daher auch in zwei Bereiche. Kapitel eins beschreibt die Grundlagen der Applikationsentwicklung, während Kapitel zwei die Architektur und Funktionsweise der, im Rahmen der ALF erstellten, Applikation „LittleProjektManager“ beschreibt. Im Anhang finden sich unter anderem Screenshots der Applikation, Diagramme und der gesamte Quellcode der Applikation.
  • 4. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 4 2 Kapitel 1 – Android Grundlagen 2.1 Was ist Android? Android ist ein hauptsächlich von Google getriebenes „Open Source Projekt“ und wurde ursprünglich als Betriebssystem für mobile Geräte entwickelt. Es findet jedoch mittlerweile auch auf anderen Geräten wie Fernsehern Anwendung. Nach meiner persönlichen Einschätzung wird es nicht lange dabei bleiben. Es gibt bereits Modelle für Uhren, Spielekonsolen und „intelligente Haushaltsgeräte“ wie Kühlschränke und Spiegel auf denen Android läuft. Im Kern besteht das Betriebssystem aus einem Linux Kernel welcher den Hardwarezugriff und die Speicherverwaltung regelt. Gleich darauf aufgesetzt läuft eine auf Java Technologie basierende virtuelle Maschine mit einer entsprechenden Android Klassenbibliothek. Die virtuelle Maschine führt dann den Bytecode bestimmter Module oder der programmierten Android Applikation aus. Um jetzt Applikationen, also Anwendungen oder Apps, zu entwickeln stellt Google ein „Java Programming Interface“ mit einer Reihe von Tools zur Verfügung. Zusätzlich können auch bereits vorhandene Softwarekomponenten mit verwendet werden. Zum Beispiel die Tastatur, die Medienwiedergabe, der Browser, die SQLite Datenbank oder OpenGL für 3D Grafik, um nur mal einen Auszug zu nennen. 2.2 Die Entwicklungsumgebung Im Prinzip könnten die Apps in einem einfachen Editor geschrieben werden und per Android Service Development Kid zu Bytecode kompiliert, um anschließend in der virtuellen Maschine des Android Gerätes ausgeführt zu werden. Das wäre aber weder zeitgemäß, noch komfortabel oder besonders effizient. Heute setzt man auf eine starke Entwicklungsumgebung. Google selbst unterstützt hier mit zahlreichen Erweiterungen (PlugIns) die Entwicklungsumgebung Eclipse, eine der meist verbreiteten IDEs (Integrated
  • 5. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 5 Development Enviroment) gerade in der Java Entwicklung. Eclipse ist ebenfalls Opensource und damit kostenlos. Dies bietet sehr viel Flexibilität und Erweiterungsmöglichkeiten. (Kurzer Einblick in Eclipse unter, 7.1 Eclipse Workbench, im Anhang auf Seite 37 ) Um nun mit der Entwicklung beginnen zu können benötigt man lediglich: • Eclipse http://www.eclipse.org/downloads/ • Android SDK (Service Development Kid) http://developer.android.com/sdk/index.html • ADT (Android Development Tools) Eclipse Plugin http://developer.android.com/tools/sdk/eclipse-adt.html Das ADT beinhaltet, neben vielen kleinen Hilfen wie einen grafischen Editor für die Benutzeroberfläche, auch einen Emulator, welcher ein beliebiges Android System emulieren kann und so ein schnelles Testen während der Entwicklung auch ohne Endgerät ermöglicht. Man kann sich mehrere verschiedene virtuelle Geräte konfigurieren und so verschiedene Displaygrößen und andere Hardwareeigenschaften emulieren und testen. 2.3 Google ADT Das Plugin bietet viele nützliche Dienste und Hilfen. Hier die wichtigsten: • Assistent zum Erstellen eines neuen Android Projektes • Assistent zum Erstellen von Attributen und Variablen • Visueller Editor für die Benutzeroberfläche der App • Einfaches Verwalten und Starten des Emulators • Ausgabe vom Systemlog-Meldungen (Logcat) des Android Systems auf dem Emulator • Android SDK Manager (Verwaltet und hält SDK aktuell)
  • 6. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 6 Android API und Besonderheiten Die Google API (Application Programming Interface) stellt die zentrale Programmierschnittstelle dar. Ohne diese ist keine Entwicklung einer Android- App möglich, da bereits bei der Darstellung bis hin zur Interaktion mit dem Nutzer über das Touchscreen native Android-Funktionen benötigt werden. Es reicht also nicht aus Java entwickeln zu können, sondern es ist zwingend notwendig sich mit der Android API auseinander zu setzen und sich an deren Regeln zu halten. Die API existiert bisher in verschiedenen Versionen. Leider sind hier nicht alle Funktionen abwärtskompatibel, was es zwingend erforderlich macht Android mitzuteilen gegen welche API Version die App kompiliert ist. Dies geschieht in der AndroidManifest.xml. Hier wird die minimale API Anforderung und die zuletzt getestete API angegeben gegen die auch kompiliert wurde. Ist die angegebene „Minimum Required SDK“ neuer als die auf dem Installationsgerät so kann die Applikation dort nicht installiert werden. Fehlt diese Angabe kann die Applikation zwar installiert werden es wird aber womöglich zu Problemen bei der Ausführung kommen und damit zu schlechten Bewertungen im Play Store.
  • 7. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 7 Abbildung 1- Eclipse New Android Application
  • 8. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 8 2.4 Grober Aufbau einer Android App Grundsätzlich ist es jedem Entwickler frei gestellt wie er seine Anwendung gestaltet und entwickelt. Android oder die API machen hier keine Vorgaben sondern sind extrem flexibel in der Wahl der Softwarearchitektur. So können bestimmte Probleme mittels XML oder direkt im Java Code gelöst werden. Google treibt aber eine modulare Softwarearchitektur voran für ein modulares Bestriebssystem. Und nur das macht auch Sinn. Die Vorteile von, im weitesten Sinne losgelösten Einzelmodulen welche als Gesamtpaket eine Applikation bilden, liegen auf der Hand. Hier wird nicht nur die einfachere Entwicklung im Team oder Softwarepflege vereinfacht, sondern auch eine stabilere und schnellere Ausführung der Applikation für das Android System ermöglicht. XML- Dateien beispielsweise welche bestimmte Eigenschaften oder das Aussehen der Applikation beschreiben, werden vor der eigentlichen Codeausführung geladen und zwar schnell und stabil. Genauso gut könnte man die komplette View, also das Aussehen, im Java-Code schreiben. Das wäre aber nicht nur schlechter Stil, sondern würde auch zu Lasten der Performance gehen im Vergleich zu dem XML-Layout. In der Softwareentwicklung gibt es bestimmte Entwurfs- oder Architekturmuster darunter auch das „Model View Controller“ Modell. Dieses Modell lässt sich auch auf Android Applikationen anwenden und beschreibt eine klare Trennung der angesprochenen drei Bereiche. Während das „Model“ den Businessbereich und die Logik darstellt ist die „View“ für das Aussehen und die Interaktion mit dem Anwender zuständig. Der „Controller“ kontrolliert nun die Nutzung des „Models“ von der „View“ aus und weiß welche „View“ welches „Model“ verwendet.
  • 9. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 9 Vereinfachte Schematische Darstellung: Activity.XML - VIEW Activity.JAVA - Controller PlainOldJavaObject – Model Zusätzlich gibt es noch eine Persistenzschicht zur dauerhaften Datenspeicherung in einer Datenbank. Im Fall von Android sind das SQLite Datenbanken welche ganz einfach über die API angelegt und genutzt werden können. Und das ist im Groben auch alles was eine Android App heute nutzt um seine Aufgaben erfüllen zu können. Im nachfolgenden Kapitel werde ich hier noch etwas mehr ins Detail gehen. Abbildung 2- MVC Architektur Quelle: wikipedia.de (MVC)
  • 10. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 10 2.5 Grundlagen der Android Entwicklung 2.5.1 View-Activity-Event-Intent Activity Die Activity stellt so zu sagen das Herzstück der Android Applikation dar mit dem entscheidenden Programmcode welcher für die Ausführung der Aplikation verantwortlich ist. Jede App muss mindestens eine Activity haben und eine davon muss als Hauptactivity definiert sein. Also die, welche beim Starten der App als erstes geladen und ausgeführt wird (Equivalent zur Main Methode eines klassischen Java-Programmes). Die Activity definiert eine „View“ zur Anzeige auf dem Bildschirm und behandelt dort auftretende Events wie beispielsweise ein Klick auf einen Button. Die Activity benutzt „Intents“ um andere Activitys zu starten. View Die View ist der sichtbare Teil der Activity und wird üblicherweise in einer XML- Layout-Datei definiert. Event Ein Event wird ausgelöst, wenn etwas geschieht wie das Klicken auf einen Button oder das Drücken des Suchen und Zurück Buttons. In der Activity muss dann ein Listener definert sein welcher auf diese Events reagiert und entsprechende Operationen durchführt. Intent Startet eine andere Activity also eine zweite Benutzeroberfläche auf dem Bildschirm. Mittels „Bundels“ können dann einfache Parameter an die Activity übergeben werden. Es können sogar Activities aus anderen Apps gestartet werden so lange diese verfügbar und im Android System als öffentlich gekennzeichnet sind. Beispielsweise könnte die Google Maps App gestartet werden und Koordinaten übergeben werden.
  • 11. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 11 Abbildung 3- Zusammenarbeit Activity und View (Quelle http://www.androidpit.de/de/android/wiki/view/Android_Anf%C3%A4nger_Workshop)
  • 12. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 12 2.5.2 Activity Lebenszyklus Da auf dem Handy die Ressourcen limitiert sind muss das Betriebssystem in der Lage sein auf den Lebenszyklus der Apps Einfluß nehmen zu können. Jede Activity hat ihren eigenen Lebenszyklus und so muss sich der Entwickler auch um die entprechenden Phasen des Zyklusses kümmern um Datenverluste oder unerwünschtes Verhalten zu vermeiden. Es gibt folgende Phasen: • onCreate() • onStart() • onPause() • onResume() • onStop() • onRestart() • onDestroy() Jede eigene Activity erbt diese Methoden von ihrer Vaterklasse Activity und kann diese überschreiben. OnPause() beispielsweise tritt ein wenn die Activity in den Hintegrund gerät weil ein Anruf herein kommt oder eine neue Activity aufgerufen wird. Vielleicht wäre es hier sinnvoll die bereits eingegebenen Daten in einer Datenbank zu speichern und bei onResume() wieder anzuzeigen. Folgendes Schaubild soll die verschiedenen Stati verdeutlichen:
  • 13. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 13 Abbildung 4 - Activity Lebenszyklus (Quelle http://www.androidpit.de/de/android/wiki/view/Android_Anf%C3%A4nger_Workshop)
  • 14. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 14 2.5.3 Die wichtigsten XML Dateien ausserhalb der Layouts Strings.xml Hier werden Variablen zur Darstellung definiert. Beispielsweise Beschriftungen und Text für die Buttons in den Views, Hilfemeldungen oder sonstige Texte. Android Manifest.xml Ist die Grundlage jeder App und unabdingbar. Hier werden Metainformationen wie das Icon, der Applikationsname und die Rechte, welche sich die Applikation einräumt, bekannt gegeben. Diese werden dem Nutzer auch vor der Installation bekannt gegeben und müssen bestätigt werden. Rechte sind beispielsweise Zugriffe auf das Netzwerk, die Kamera oder die Kontaktdaten. Ausserdem sollte noch die vorausgesetzte API Version angegeben werden, um zu verhindern, dass die App auf nicht lauffähigen Geräten installiert werden kann. Exemplarisches Beispiel einer AdroidManifest.xml mit Erläuterung. Abbildung 5- AndroidManifest.xml (Quelle http://www.androidpit.de/de/android/wiki/view/Android_Anf%C3%A4nger_Workshop/)
  • 15. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 15 2.5.4 Persistenz und Datenspeicherung in Adnroid Zur persistenten Datenspeicherung bietet Android eine einfache Art SQLite als schlankes Datenbanksystem an. Durch das Erben und Überschreiben der Klasse SQLiteOpenHelper wird es erleichtert eigene Datenbanken an zu legen, welche dann per default als Datei auf der SD-Karte gespeichert werden. SQLite ist eine Open-Source-Datenbank, die in Android eingebettet ist. SQLite unterstützt Standardfunktionen von relationalen Datenbanken wie SQL-Syntax, Transaktionen und Prepared Statements. Darüber hinaus bedarf es nur wenig Speicher zur Laufzeit (ca. 250 KByte). SQLite unterstützt die Datentypen TEXT (ähnlich String in Java), INTEGER (ähnlich wie long in Java) und REAL (ähnlich wie double in Java). Alle anderen Formate müssen vor dem Speichern in einen dieser Datentypen konvertiert werden.
  • 16. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 16 3 Kapitel 2 - App Dokumentation LittleProjectManager 3.1 Beschreibung der Applikation Die App soll eine einfache Verwaltung von Projekten und seinen ToDo`s möglich machen. Zusätzlich soll man die Zeit messen können wie lange man für das jeweilige Projekt gearbeitet hat. Der Anwendungsfall kommt aus der Praxis. Denn bei kleinen oder mittelgroßen Projekten wird häufig vergessen die eigene Zeit zu messen um hinterher die geschätzte Zeit und die verbrauchte Zeit gegenüber stellen zu können. Ausserdem soll es helfen dem Kunden die korrekten Zeiten in Rechnung zu stellen. Die Möglichkeit ToDo`s anzulegen dient lediglich der Übersichtlichkeit und stellt eine Art Notizzettel für das Projekt dar. Ich habe mich bewusst dagegen entschieden die Zeiten für einzelne ToDos zu tracken. Dies wäre zwar auf Grund der Datenbankstruktur möglich findet aber in der Praxis wenig Relevanz da zumindest bei den Projekten kleinerer Größenordnung diese Zeiten keine Rolle spielen und das Buchen für den Nutzer zu aufwendig wäre. Die Applikation bildet folgende funktionale und technische Leistungsmerkmale: • Projekte anlegen und entfernen • ToDo`s für Projekte anlegen und entfernen • Einfaches „Einbuchen“ bei Arbeitsbeginn • Einfaches „Ausbuchen“ bei Arbeitsende • Zusätzlich soll auch ein manuelles Buchen von Zeiten möglich sein • Die App soll direkt nach Buchung die aktuelle Zeit berechnen und anzeigen Technische Leistungsmerkmale: • Daten in der SQLite Datenbank speichern • Intuitive Bedienung über das Touch-Display
  • 17. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 17 • Optimiert für die Benutzung mit Smartphone, sollte aber auch auf einem Tablet funktionsfähig sein • Android spezifische Bedienelemente wie der Zurück Button und Menü Button (vor Android 3.0) sollten unterstützt werden Screenshots zur Verdeutlichung finden sich im Anhang unter 7.2 Screenshots LittleProjectManager auf Seite 38.
  • 18. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 18 3.2 Architektur und Funktionsweise der Applikation Hierzu empfiehlt es sich erst mal einen Blick auf das Schaubild aus Anlage 7.3 Architekturschaubild auf Seite 40 zu werfen. Dort ist ein Architekturdiagramm der Applikation abgebildet unter Berücksichtigung des MVC Entwurfsmusters. Es beinhaltet alle funktional wichtigen Klassen und XML Dateien der Applikation und deren Abhängigkeiten, welche nun im Detail erläutert werden. Es empfiehlt sich vorher im ersten Kapitel den Teil „Grober Aufbau einer Android Applikation“ gelesen zu haben. 3.2.1 Activity-View und Layout (VIEW) In der VIEW befinden sich die XML Dateien. Drei Activity-Views und ein Layout. Die activity_project_view und die activity_todo_view bestehen beide aus ListViews um eine Liste der jeweiligen Objekte, eben Projekte und Todos, darstellen zu können. Bei beiden kann über das Menü das Layout add_item.xml aufgerufen werden. Dies ist eine Art Formular, um neue Todo's oder Projekte an zu legen. Das Add-Item-Layout besteht aus einem Textfeld und einem Button und wird hier einmal exemplarisch dargestellt: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <EditText android:id="@+id/editText1" android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" android:inputType="textMultiLine" > <requestFocus /> </EditText>
  • 19. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 19 <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/Add" android:onClick="AddClick" /> </LinearLayout> Das ganze Layout besteht aus einem LinearLayout innerhalb dessen befinden sich ein EditText Feld zum Eingeben des neuen Projektes oder des Todo und ein Button zum Bestätigen. Zusätzlich werden Angaben zur Größe und Anordnung des jeweiligen Elementes gemacht. Die android:id beschreibt den Namen über den auf das Element später im JAVA Code zugegriffen werden kann und android:text="@string/Add gibt an welcher Text auf dem Button stehen soll. Unter android:id="@+id/editText1" kann das Textfeld in der JavaKlasse also der jeweiligen Activity, welche das Layout gestartet hat, erreicht werden. Und android:onClick="AddClick" gibt an, dass, wenn der Button Add gedrückt wird, in der Activity die Methode AddClick() ausgeführt wird. Die Dritte und letzte Activity-View ist die activity_time_manager.xml welche für die Zeitbuchungen und die Anzeige der Zeiten zuständig ist. Dementsprechend viele Elemente sind hier vorhanden:  ein Button zur Anzeig des aktuellen Datums  ein Button welcher die aktuelle Zeit anzeigt  ein Button zum Einbuchen  ein Button zum Ausbuchen  einen Button um nur die Zeit in Stunden und Minuten auf das Projekt nachträglich als Arbeitszeit zu buchen. Wird der Button für Datum gedrückt so öffnet sich ein spezielles Auswahlmenü von Android zur Datumsauswahl und bei der Zeit ist es das gleiche. Diese Auswahldialoge müssen als so genannte Dialogfragmente ausprogrammiert
  • 20. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 20 werden. 3.2.2 Activitys (Controller) Jede Activity-View hat auch ihre eigene Klasse welche die verschiedenen Stati des Lebenszyklus und die Interaktion mit dem Benutzer behandelt. Die Hauptactivity ist in der AndroidManifest.xml beschrieben. Bei dieser Applikation handelt es sich um die Activity Project_View.java. Jede Activity die als solche fungieren soll hat als Vaterklasse die Klasse android.app.Activity und überschreibt mindestens eine Methode: Die onCreate() Methode, welche in unserem Fall nichts weiter macht als sich aktuelle Daten aus der Datenbank zu holen und darzustellen. Zusätzlich wird noch das Optionsmenu deklariert und auf das Drücken von Menüeinträgen, Listeinträgen und Buttons mit entsprechendem Programmcode reagiert. ProjectView.java Füllt die ListView mit Projekten. Projekte können ausgewählt und anschließend gelöscht werden. Genauso gut können nach Auswahl eines Projektes die dazugehörigen Todos geladen werden. Dies geschieht durch das Aufrufen der MyTodosOverview und die Übergabe der Projektid des ausgewählten Objektes. Ausserdem kann das Layout add_item.xml aufgerufen werden und neue Projekte angelegt werden. Kurze Beschreibung der Methoden: onCreate() Legt die Activity-View fest welche angezeigt werden soll. Ruft Hilsmethode showValuesFromDB() auf. showValuesFromDB() Holt sich die Projekte aus der Datenbank und setzt vorhandene Values in die Liste.
  • 21. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 21 Aktiviert OnClickListner welcher das markierte Objekt der Liste festhält und einfärbt. onCreateOptionsMenu() Legt das Menü Fest welches angezeigt wird wenn auf den Menü Button gedrückt wird. onOptionsItemSelected(MenuItem item) Deklariert pro betätigtem Menüeintrag was passieren soll. AddClick(View view) Methode wird aufgerufen wenn im add_item.xml Layout der Button Add gedrückt wird. Der Inhalt des Textfeldes aus dem Layout wird als Projekt in die Datenbank geschrieben MyTodosOverview.java Funktioniert genauso wie die ProjectView.java, ausser dass es sich hierbei um die Todos handelt, die angezeigt, verwaltet und in die Datenbank geschrieben, sowie dort gelöscht werden können. TimeManager.java Diese Activity ist die Aufwendigste in der Applikation. Sie übernimmt nicht nur das Eintragen von Buchungen in die Datenbank sondern ist auch für die aktuelle Anzeige von Datum und Uhrzeit zuständig. Außerdem errechnet sie bei jeder Buchung die Arbeitszeit neu, sofern möglich und zeigt diese Information direkt über die VIEW an. Die beiden Dialoge zur Datums- und Zeitauswahl werden von ihr gestartet und beobachtet um Änderungen direkt zu erkennen. Daher handelt es sich auch um eine FragmentActivity welche ihrerseits erweiterte Funktionen anbietet als ihre Vaterklasse Activity.
  • 22. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 22 Die ganze Berechnung der Zeit erfolgt über ein java.util.Calendar Objekt während die Anzeige über java.text.SimpleDateFormat formatiert wird. Erläuterung der wichtigsten Methoden: onCreate() Legt die Activity-View fest welche angezeigt werden soll. Ermittelt die aktuelle Zeit Steuert die interne Hilfsmethode setTimeOnView(Calendar c) und setDateOnView(Calendar c) an. Steuert interne Hilfsmethode addTimeandDateButtonListners() an. onResume() Ermittelt das aktuelle Projekt und zeigt dessen Namen an sowie die bisher gebuchte Arbeitszeit. Dies geschieht in der onResume() Methode so, dass die Anzeige nicht nur nach dem Erstellen der Activity aktualisiert wird sondern auch wenn die Activity im Hintergrund war. setTimeOnView(Calendar c) Zeigt die aktuelle Zeit im Button an setDateOnView(Calendar c) Zeigt aktuelles Datum im Datum Button an addTimeandDateButtonListners() Listner welcher auf das Drücken einer der Buttons reagiert checkin(), checkout() und justbookthetime() Bucht die entsprechende Zeit in die Datenbank. Steuert CalcWorkingTime() an CalcWorkingTime() Errechnet die Arbeitszeit wenn möglich. Es wird überprüft ob genau so viele
  • 23. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 23 Ein- wie Ausbuchungen vorhanden sind, errechnet dann die neue Arbeitszeit und schreibt diese Informationen in die Datenbank. ShowDatePicker() und showTimePicker() Zeigen die Dialoge zur Auswahl von Datum und Zeit an OnTimeSetListener() und OnDateSetListener() Reagieren auf die Zeitauswahl in dem sie die Zeit im Calendar Objekt ändern und die ausgewählte Zeiten auf den Buttons der View visualisieren. 3.2.3 Dialogfragmente (Controller) Zur Auswahl von Datum und Zeit werden TimePicker und DatePicker verwendet. Dies sind Objekte um es dem Nutzer so komfortabel wie möglich zu machen über den Touchscreen Datum und Zeiteingaben zu tätigen. Diese werden von Android zur Verfügung gestellt. Um sie nutzen zu können, müssen sie in so genannte Dialogfragmente verpackt werden. Also Dialoge welche erscheinen während die eigentliche Activity im Hintergrund noch aktiv ist. Also weder in den Status onPause() gesetzt, noch beendet wird. Wird also nun in der Time_Manager.java Activity auf den Button mit dem Datum gedrückt so wird das DatePickerFragment gestartet. Über einen Datencontainer, bei Android das Bundle, werden die aktuellen Werte zur Anzeige übergeben und bei Auswahl durch den Nutzer die ausgewählten Werte zurück an die Activity übergeben.
  • 24. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 24 3.2.4 Plain-Old-Java-Objects (Model) Hier finden sich klassische Java Objekte welche in der Applikation durch alle Instanzen hindurch genutzt werden wie Todo, TimeEntry oder Project. Klassisch deshalb weil sie als Vaterklasse lediglich die Klasse Object besitzen. Diese Objekte stellen immer jeweils ein Listeneintrag in der View oder eine Zeile in der Datenbank dar. Dementsprechend sind auch die Attribute pro Klasse gewählt: 3.2.5 DataAccessObjects (Model) Hierunter fallen die drei Klassen ProjectDatasource.java, TimeTableDatasource.java und TodosDatasource.java. Die Aufgabe des DAO ist das Erlauben des Zugriffs auf die Datenbank und das Anbieten von Methoden fürs Abholen und Schreiben von Daten. Dies beinhaltet den Verbindungsauf- und Abbau genauso wie das Zusammenbauen bestimmter SQL-Abfragen zum Herausholen aller oder nur eines bestimmten Datensatzes mittels Fremdschlüssel. Das Ergebnis aus der Datenbank kommt als so genannter Curser zurück und wird nicht einfach an die aufrufende Klasse zurückgegeben. Es werden POJOs (Plain-Old-Java-Objects) vom jeweiligen Typ erzeugt und einzeln oder in einer Liste zurück gegeben. Dazu wurden in Abbildung 6 - Klassendiagramm Models
  • 25. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 25 der Klasse als privat gekennzeichnete Hilfsmethoden geschrieben. 3.2.6 MySQLiteHelper und seine Tabellenklassen (Model) MySQLiteHelper hat als Vaterklasse SQLiteOpenHelper und überschreibt onCreate() und onUpgrade(). OnCreate() wird vom Framework aufgerufen wenn die Datenbank noch nicht existiert und onUpdate() wenn sich die Versionsnummer ändert. Beide Methoden bekommen ein Datenbankobjekt beim Aufruf übergeben, welches die Datenbank repräsentiert. In der Applikation gibt es für jede Tabelle eine eigene Klasse: • ProjectTable.java • TodoTable.java • TimeTabl.java Jede dieser Tabellenklassen hat statische Variablen für den Tabellennamen und die Spalten. Ausserdem besitzt jede Klasse ihre eigene statische onCreate() und onUpdate() Methode in der der SQL-Befehl zum Erstellen und Updaten der Tabellen ausformuliert ist. Hier wird auch angegeben welche Datentypen in die Spalten gehören und ob es sich dabei um Schlüssel handelt. Als Beispiel hier ein Auszug der Klasse ProjectTable, welche auch genau diese Tabelle MYPROJECTS repräsentiert: public class ProjectTable // Database table public static final String TABLE_PJ = "myprojects"; public static final String COLUMN_ID = "_id"; public static final String COLUM_NAME = "name"; public static final String COLUM_WORKTIME = "worktime"; //SQL CREATE Statement private static final String TABLE_CREATE_MYPROJECTS ="" +"create table " +TABLE_PJ +" ( " +COLUMN_ID+ " integer primary key autoincrement, " +COLUM_NAME +" text not null, " +COLUM_WORKTIME +" integer" +");"; /*
  • 26. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 26 * Tabelle erstellen */ public static void onCreate(SQLiteDatabase db) { db.execSQL(TABLE_CREATE_MYPROJECTS); } Es wird von Android empfohlen als Primärschlüssel _id zu verwenden so wie hier geschehen. Zusätzlich wird noch durch „autoincrement“ angegeben, dass die Spalte automatisch hoch gezählt wird. Die Klasse MySQLiteHelper führt jetzt in seiner eigenen onCreate() Methode nur noch die statischen onCreate() Methoden der jeweiligen Tabellen aus: Auszug aus public class MySQLiteHelper @Override public void onCreate(SQLiteDatabase db) { ProjectTable.onCreate(db); TodoTable.onCreate(db); TimeTable.onCreate(db); } So ist sichergestellt, dass die Datenbanken alle angelegt sind und von Objekten der Datasource Klasse darauf zu gegriffen werden kann. 3.3 SQLite Datenbank Zur Datenspeicherung bietet Android eine sehr einfache Möglichkeit eine SQLite Datenbank an zu legen. Der LittleProjektManager greift darauf zu. Die Daten werden zwecks Normalisierung und einer einfachen Datenhaltung in drei Tabellen gespeichert. Android empfiehlt für jede Tabelle eine Spalte _id als Primärschlüssel zu verwenden. In unserem Falle deklarieren wir die Spalte _id zusätzlich noch als „autoincrement“, so dass sie bei jedem Eintrag automatisch hoch gezählt wird und uns die Verknüpfung somit vereinfacht. In SQLite gibt es vier Datentypen:
  • 27. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 27 SQLite Datentyp Equivalent in JAVA INTEGER Long TEXT String REAL Double BLOB Data Die Datenbank selbst wird von Android auf der SD-Karte unter dem Ordner „data“ und dem jeweiligen Applikationsnamen als eine Datei gespeichert. 3.3.1 Datenbankstruktur Abbildung 7 - Datenbankdiagramm MYPROJECTS Beinhaltet alle relevanten Informationen zum Projekt. Der eingegebene Name als Text, eine _id als Primärschlüssel, der automatisch hoch gezählt wird und die workingtime als Integer. Die Workingtime ist zu Beginn 0 und wird dann je nach Buchungen hochgezählt und überschrieben. Einfache Zeitbuchen werden direkt und nur hier gespeichert. Ein- und Ausbuchungen mit Datumsangaben kommen in die Tabelle TIMETABLE. TODO
  • 28. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 28 Ist eine unabhängige Tabelle mit eigener _id als Primärschlüssel und der Aufgabe todo selbst als Text. Da alle Todos einem Projekt zugeordnet werden müssen, sind sie über die pj_id als Fremdschlüssel mit der Tabelle MYPROJECTS verbunden. Es besteht eine 1-zu-n Beziehung. Ein Projekt kann viele Todos haben aber ein Todo kann nur zu einem Projekt gehören. TIMETABLE Hier werden alle Ein- und Ausbuchungen gespeichert, welche nicht nur als Zeitbuchung, sondern mit einer kompletten Zeitangabe gebucht werden also Datum und Uhrzeit. Beides zusammen wird im Java Code als Ganzzahl im Datentyp long dargestellt und kann daher auch so in der Datenbank eingetragen werden. Neben dem Primärschlüssel _id wird die Zeit als long, und datetime als Integer gespeichert. Unter entrytype wird eine 0 fürs Einbuchen und eine 1 fürs Ausbuchen geschrieben und die pj_id ist wieder die Verbindung in Form eines Fremdschlüssels zur Tabelle MYPROJECTS. Auch hier besteht vom Projekt der Tabelle MYPROJECTS ausgehend eine 1-zu-n Beziehung.
  • 29. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 29 3.4 Projekt und Paketstruktur 3.4.1 Pakete und Klassen Da der Paketname eindeutig für die Applikation sein soll, um gezielt der eigenen Applikation zugeordnet werden zu können, wurde hier de.thorstenweiskopf.lpm gewählt. Das Kürzel de für die Länderdomäne, thorstenweiskopf als autor und lpm als kürzel für den Applikationsname LittleProjectManager. Danach werden noch Unterpakete verwendet um die unterschiedlichen Aufgabenbereiche darzustellen:
  • 30. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 30 src: Hier liegen die eigenen Klassen. Unter dem Hauptpaket befinden sich die drei Activitys. .databse: alle datenbankrelevanten Klassen: Der SQLiteHelper welcher die Datenbank erstellt und updatet sowie die drei Datasources zum Zugriff auf die Datenbank. .tables: Tabellen selbst in Form von Java- Klassen die vom SQLiteHelper genutzt werden. .dialogframents ZeitAuswahlDialoge .model Daten Modelle für die verwendeten Datenobjekte: Projekt, Zeiteintrag und Todo. gen: Hier sind die von Android generierten Klassen abgelegt. Am wichtigsten ist die Klasse R welche über Referenzvariablen alle Ressourcen zur Verfügung stellt. Ressourcen sind: Layouts, Activity-Views, Strings, Menüs, Bilder usw.
  • 31. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 31 3.4.2 Projektdateien und Ressourcen Das Android Projekt besteht allerdings aus mehr als nur den Java-Klassen selbst. Es gibt noch ein Ressourcen Verzeichnis mit Inhalten und die AndroidManifest.xml:
  • 32. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 32 /res:Ordner für Resource-Dateien /res/drawable-hdpi: Logos in hoher Auflösung /res/drawable-ldpi Logos in niedriger Auflösung /res/drawable-mdpi: Logos in mittlerer Auflösung /res/drawable-xhdpi:Logos in sehr hoher Auflösung /res/layout alle Layout-Definitionen Activity-Views und Layouts /res/menu: Menüs activity_project_view: Menü für die Projektübersicht activity_project_view: Menü für die ToDos /res/values: Variablen strings.xml: String-Definitionen für Buttons und Überschriften styles.xml: Erscheinungsbild der App AndroidManifest.xml:"Manifest"-Datei, definiert Infos wie Name, Logo und Haupt-Activity default.properties:Projekt-Eigenschaften
  • 33. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 33 4 Ausblick und Fazit Die Applikation „LittleProjektMananer“ hat noch Optimierungspotential hinsichtlich des Designs. Ausserdem fehlt noch eine Implementierung der seit Android 4.0 vorhandenen „ActionBar“ welche das Menü ersetzen soll. Eine Möglichkeit für statistische Auswertungen über die bereits getätigten Buchungen ist auch denkbar. Sind diese Leistungsmerkmale realisiert, was sich bereits in Planung befindet, steht einer Veröffentlichung über den Google „Playstore“ nichts mehr im Wege. Als Fazit für Android selbst ist zu sagen, dass Android eine solide Basis bietet native Applikationen zu entwickeln. Der modulare Aufbau bietet gute Möglichkeiten für Erweiterungen und die Realisierung von größeren Projekten. Diese Gründe und der Fakt, dass das Betriebssystem auf dem Vormarsch in vielen Bereichen elektronischer Geräte ist, verspricht Android und den Applikationsentwicklern eine aussichtsreiche Zukunft.
  • 34. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 34 5 Abbildungsverzeichnis Abbildung 1 - Eclipse New Android Application .................................................. 7 Abbildung 2 - MVC Architektur ........................................................................... 9 Abbildung 3 - Zusammenarbeit Activity und View ........................................... 11 Abbildung 4 - Activity Lebenszyklus ............................................................... 13 Abbildung 5 - AndroidManifest.xml ................................................................. 14 Abbildung 6 - Klassendiagramm Models .......................................................... 24 Abbildung 7 - Datenbankdiagramm .................................................................. 27
  • 35. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 35 6 Abkürzungsverzeichnis App Application (Anwendung) IDE Integrated Development Enviroment SDK Service Development Kit ADT Android Development Tools API Application Programming Interface MVC Model View Controller (Softwarearchitektur) POJO Plain Old Java Object (“simple” Javaklassen)
  • 36. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 36 7 Anlagen
  • 37. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 37 7.1 Eclipse Workbench (QUELLE: http://www.admin-wissen.de/tutorials/eclipse_workshop/ueberblick_workbench.html) Zu Eclipse selbst und der Benutzung gibt es eine Reihe von Büchern und Seminare. Ich möchte hier nur einen Auszug aus www.admin-wissen.de einbinden welcher ganz gut die Benutzung erläutert: 1. Im Bereich 1 findest einen Überblick über die vorhandenen Projekte. Du kannst zwischen den Projekten navigieren und Dateien öffnen, erstellen oder Ordner in denProjekten anlegen etc. 2. In diesem Bereich ist der Editor zu finden. Im Editor kannst du den Sourcecode schreiben, er wird farbig hervorgehoben und Fehler die Eclipse im Vorfeld erkennt werden markiert. In manchen Fällen signalisiert Eclipse mit einer Glühbirne, wie der Fehler möglicherweise behoben werden kann. 3. Hier befindet sich die Outline. Darin findest du wissenswertes über die im Moment geöffnete Datei. Bei einer Klasses siehst du hier die Attribute und Methoden und kannst sie sortieren oder anders in der Outline organisieren. Durch einen Klick auf die Methode kommst du z.B. direkt an die Stelle im Quelltext wo sie implementiert ist. Dadurch bekommt man bei umfangreichen Klassen schnell einen Überblick welche Methoden die Klasse bietet. 4. In diesem Bereich findest du verschiedene Konsolenausgaben. Eine mögliche Konsolenausgabe ist z.B. ein Kompilierungsfehler oder die Ausgabe des laufenden Programms.
  • 38. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 38 7.2 Screenshots LittleProjectManager Projektübersicht Projektübersicht mit Auswahl und Menü Add Item Formular Todoübersicht mit Auswahl und Menü
  • 39. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 39 Arbeitszeitverwaltung zum Buchen und Anzeigen von Zeiten Dialog zur Zeitauswahl wenn entsprechender Button gedrückt wurde
  • 40. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 40 7.3 Architekturschaubild
  • 41. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 41 7.4 Quellcode der Applikation AndroidManifest.xml <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="de.thorstenweiskopf.lpm" android:versionCode="1" android:versionName="1.0" > <!-- welches min und max sdk wird supported von dieser app --> <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="15" /> <!-- applicationbeschreibung--> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <!-- alle Activitys also Views --> <activity android:name=".MyTodosOverview" android:label="@string/title_activity_my_todos_overview" > </activity> <activity android:name=".ProjectView" android:label="@string/title_activity_project_view" android:configChanges="orientation|keyboardHidden|keyboard|screenSize" > <intent-filter> <!-- Hauptactivity soll geöffnet werden beim start --> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".TimeManager" android:label="@string/title_activity_time_manager" > </activity> </application> </manifest>
  • 42. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 42 stringx.xml <resources> <string name="app_name">LittleProjectManager</string> <string name="title_activity_my_todos_overview">My Todos</string> <string name="Add">Add</string> <string name="Remove">Remove</string> <string name="title_activity_my_todo_add">Add a Todo</string> <string name="title_activity_project_view">My Projects</string> <string name="title_activity_time_manager">My Project Times</string> <string name="menu_settings">Settings</string> <string name="menu_addpj">Add Project</string> <string name="menu_showtodos">Show ToDo Items</string> <string name="menu_remove_pj">Remove Project</string> <string name="menu_timemanager">Project TimeManagement</string> <string name="menu_timestats">Show Workingtime</string> <string name="time_checkinbutton">Check In</string> <string name="time_checkoutbutton">Check Out</string> <string name="time_hourbutton">Timebooking (Hour and Minute)</string> </resources>
  • 43. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 43 ACTIVITY-VIEWS activity_project_view.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <ListView android:id="@+id/listView1" android:layout_width="match_parent" android:layout_height="wrap_content" > </ListView> </RelativeLayout> activity_todos_view.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <LinearLayout android:layout_height="wrap_content" android:layout_width="wrap_content" > <TextView android:id="@+id/todo_lable" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/title_activity_my_todos_overview" android:textSize="30dp" /> </LinearLayout> <LinearLayout android:layout_height="match_parent" android:layout_width="match_parent" > <ListView android:id="@+id/listView1" android:layout_width="match_parent" android:layout_height="wrap_content" > </ListView> </LinearLayout> </LinearLayout>
  • 44. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 44 additem.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <EditText android:id="@+id/editText1" android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" android:inputType="textMultiLine" > <requestFocus /> </EditText> <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/Add" android:onClick="AddClick" /> </LinearLayout>
  • 45. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 45 activity_time_manager_view.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:id="@+id/Text_ProjectLable" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="5dip" android:text="Large Text" android:textAppearance="?android:attr/textAppearanceLarge" android:textSize="30dp" /> <TextView android:id="@+id/Text_ProjectTime" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="10dip" android:text="Large Text" android:textAppearance="?android:attr/textAppearanceLarge" /> <Button android:id="@+id/button_date" android:layout_width="199dp" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="5dip" android:text="Button" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:orientation="horizontal" > <Button android:id="@+id/button_time" android:layout_width="198dp" android:layout_height="wrap_content" android:text="Button" /> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" > <Button android:id="@+id/button_checkin" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_margin="10dip" android:text="@string/time_checkinbutton" />
  • 46. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 46 <Button android:id="@+id/button_checkout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="10dip" android:text="@string/time_checkoutbutton" /> </LinearLayout> <Button android:id="@+id/button_hours" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="@string/time_hourbutton" /> </LinearLayout>
  • 47. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 47 MENUS acitivity_project_view <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/addpj" android:title="@string/menu_addpj"></item> <item android:id="@+id/showTodos" android:title="@string/menu_showtodos"></item> <item android:id="@+id/removepj" android:title="@string/menu_remove_pj"></item> <item android:id="@+id/timemanager" android:title="@string/menu_timemanager"></item> </menu> activity_todos_view <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/addpj" android:title="@string/menu_addpj"></item> <item android:id="@+id/showTodos" android:title="@string/menu_showtodos"></item> <item android:id="@+id/removepj" android:title="@string/menu_remove_pj"></item> <item android:id="@+id/timemanager" android:title="@string/menu_timemanager"></item> </menu>
  • 48. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 48 JAVA KLASSEN MyTodosOverview.java package de.thorstenweiskopf.lpm; import java.util.ArrayList; import java.util.List; import de.thorstenweiskopf.lpm.database.TodosDatasource; import de.thorstenweiskopf.lpm.model.ToDo; import de.thorstenweiskopf.lpm.R; import android.os.Bundle; import android.app.Activity; import android.graphics.Color; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; public class MyTodosOverview extends Activity { ArrayAdapter<ToDo> adapter; //Variablen der Todo Liste public static List<ToDo> values = new ArrayList<ToDo>(); int selectedItem = -999; private String projectname; private long projectid; //For Database Use private TodosDatasource datasource; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_todos_view); //Datasource benutzen datasource = new TodosDatasource(this); Bundle extras = getIntent().getExtras(); if (extras == null) { return; } // Get data via the key from Intent projectname = extras.getString("ProjectName"); projectid = extras.getLong("ProjectId"); if (projectname != null) { // Show projectname as lable
  • 49. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 49 TextView lable = (TextView) findViewById(R.id.todo_lable); lable.setText(projectname); } showValuesFromDB(projectid); } /* * Methode um mittels projectid die entsprechenden Todos anzuzeigen */ private void showValuesFromDB(long projectid) { values.clear(); try { datasource.open(); values = datasource.getAllTodosFromProject(Long.toString(projectid)); datasource.close(); } catch (Exception ex) { Toast.makeText(this, ex.toString(), Toast.LENGTH_LONG).show(); } adapter = new ArrayAdapter<ToDo>(this, android.R.layout.simple_list_item_1, android.R.id.text1, values); // Assign adapter to ListView ListView listView = (ListView) findViewById(R.id.listView1); listView.setAdapter(adapter); //Set a OnClickListner to the ListView to choose one todo listView.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { selectedItem = position; //the choosen one //change bgcolor of the selected item for(int a = 0; a < parent.getChildCount(); a++) { parent.getChildAt(a).setBackgroundColor(Color.WHITE); } view.setBackgroundColor(Color.GRAY); openOptionsMenu(); } }); } /* * Methode setzt alle vorhandene Todos in die Liste * DERZEIT nicht genutzt */ private void showValuesFromDB() { values.clear(); try { datasource.open(); values = datasource.getAllTodos(); datasource.close(); } catch (Exception ex) { Toast.makeText(this, ex.toString(), Toast.LENGTH_LONG).show(); } adapter = new ArrayAdapter<ToDo>(this, android.R.layout.simple_list_item_1, android.R.id.text1, values); // Assign adapter to ListView ListView listView = (ListView) findViewById(R.id.listView1);
  • 50. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 50 listView.setAdapter(adapter); //Set a OnClickListner to the ListView to choose one todo listView.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { selectedItem = position; //the choosen one //change bgcolor of the selected item for(int a = 0; a < parent.getChildCount(); a++) { parent.getChildAt(a).setBackgroundColor(Color.WHITE); } view.setBackgroundColor(Color.GRAY); openOptionsMenu(); } }); } /* * (non-Javadoc) * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu) * OptionsMenuStuff */ @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_todos_view, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.Add){ ListView listView = (ListView) findViewById(R.id.listView1); listView.setAdapter(adapter); // show the add view setContentView(R.layout.additem); } else if (item.getItemId() == R.id.Remove) { if (selectedItem != -999){ ToDo todo = adapter.getItem(selectedItem); selectedItem = -999; try { datasource.open(); datasource.removeTodo(todo); datasource.close(); } catch (Exception ex) { Toast.makeText(this, ex.toString(), Toast.LENGTH_LONG) .show(); } // show the main view setContentView(R.layout.activity_todos_view); showValuesFromDB(); } else{ Toast.makeText(this, "Please choose a Item from List", Toast.LENGTH_LONG).show(); } }
  • 51. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 51 return super.onOptionsItemSelected(item); } /* * Method of the layout additem.xml * Beschrieben im Layout als AddClick */ public void AddClick(View view){ if (view.getId() == R.id.button1){ EditText text = (EditText)findViewById(R.id.editText1); //values.add(text.getText().toString()); //put the new value in the database try { datasource.open(); datasource.creatTodo(text.getText().toString(), Long.toString(projectid));//Fehlt noch die Projektid vom DB Objekt Projekt datasource.close(); } catch (Exception ex) { Toast.makeText(this, ex.toString(), Toast.LENGTH_LONG).show(); } //show the main view setContentView(R.layout.activity_todos_view); // Show projectname as lable TextView lable = (TextView) findViewById(R.id.todo_lable); lable.setText(projectname); showValuesFromDB(projectid); } } }
  • 52. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 52 ProjectView.java package de.thorstenweiskopf.lpm; import java.util.ArrayList; import java.util.List; import de.thorstenweiskopf.lpm.database.ProjectDatasource; import de.thorstenweiskopf.lpm.database.TodosDatasource; import de.thorstenweiskopf.lpm.model.Project; import de.thorstenweiskopf.lpm.model.ToDo; import de.thorstenweiskopf.lpm.R; import android.os.Bundle; import android.app.Activity; import android.content.Intent; import android.graphics.Color; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.ListView; import android.widget.Toast; import android.widget.AdapterView.OnItemClickListener; public class ProjectView extends Activity { ArrayAdapter<Project> adapter; //Adapter to fill the P //Variablen der Projekte Liste public static List<Project> values = new ArrayList<Project>(); int selectedItem = -999; private ProjectDatasource datasource; //Schnittstelle zur Datenbank /* * (non-Javadoc) * @see android.app.Activity#onCreate(android.os.Bundle) * wird aufgerufen wenn android Activity anzeigen soll */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_project_view); datasource = new ProjectDatasource(this); showValuesFromDB(); } /* * Methode holt sich Projekte aus DB * und setzt vorhandene Values in die Liste */ private void showValuesFromDB() { values.clear(); try { datasource.open(); values = datasource.getAllProjects(); datasource.close();
  • 53. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 53 } catch (Exception ex) { Toast.makeText(this, ex.toString(), Toast.LENGTH_LONG).show(); //Fehler ausgabe ToDo: Überschreiben mit eigenem Fehlertext } adapter = new ArrayAdapter<Project>(this, android.R.layout.simple_list_item_1, android.R.id.text1, values); // Assign adapter zur ListView ListView listView = (ListView) findViewById(R.id.listView1); listView.setAdapter(adapter); /* * Setze Onclicklistner auf die ListView um projekte auswählen zu könnnen. */ listView.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { selectedItem = position; // the choosen one // change bgcolor of the selected item for (int a = 0; a < parent.getChildCount(); a++) { parent.getChildAt(a).setBackgroundColor(Color.WHITE); } view.setBackgroundColor(Color.GRAY); openOptionsMenu(); } }); } /* * (non-Javadoc) * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu) * OptionsMenuStuff */ @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_project_view, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.addpj) { ListView listView = (ListView) findViewById(R.id.listView1); listView.setAdapter(adapter); // show the add view -> No Activity just a "Formular" Layout to switch into setContentView(R.layout.additem); } else if (item.getItemId() == R.id.removepj) { if (selectedItem != -999) { Project project = adapter.getItem(selectedItem); selectedItem = -999; try { datasource.open(); datasource.removeProject(project); datasource.close(); } catch (Exception ex) { Toast.makeText(this, ex.toString(), Toast.LENGTH_LONG) .show(); }
  • 54. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 54 // show the main view setContentView(R.layout.activity_project_view); showValuesFromDB(); } else { Toast.makeText(this, "Please choose a Item from List", Toast.LENGTH_LONG).show(); } } else if (item.getItemId() == R.id.showTodos) { //Intent nutzen um andere Activity zu starten und Werte zu übergen Intent i = new Intent(this, MyTodosOverview.class); Project project = adapter.getItem(selectedItem); i.putExtra("ProjectId", project.getId()); i.putExtra("ProjectName", project.getName()); startActivity(i); } else if (item.getItemId() == R.id.timemanager){ if (selectedItem != -999) { Intent i = new Intent(this, TimeManager.class); Project project = adapter.getItem(selectedItem); i.putExtra("ProjectId", project.getId()); i.putExtra("ProjectName", project.getName()); i.putExtra("workingtime", project.getTime()); startActivity(i); } else { Toast.makeText(this, "Please choose a Item from List", Toast.LENGTH_LONG).show(); } } return super.onOptionsItemSelected(item); } /* * Method of the Formular Layout additem.xml * Beschrieben im Layout als AddClick */ public void AddClick(View view) { if (view.getId() == R.id.button1) { EditText text = (EditText) findViewById(R.id.editText1); // values.add(text.getText().toString()); // put the new value in the database try { datasource.open(); datasource.creatProject(text.getText().toString()); datasource.close(); } catch (Exception ex) { Toast.makeText(this, ex.toString(), Toast.LENGTH_LONG).show(); } // show the main view setContentView(R.layout.activity_project_view); showValuesFromDB(); } } }
  • 55. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 55 TimeManager.java package de.thorstenweiskopf.lpm; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import android.app.Activity; import android.app.DatePickerDialog; import android.app.TimePickerDialog; import android.app.DatePickerDialog.OnDateSetListener; import android.app.TimePickerDialog.OnTimeSetListener; import android.os.Bundle; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.DatePicker; import android.widget.TextView; import android.widget.TimePicker; import android.widget.Toast; import de.thorstenweiskopf.lpm.database.ProjectDatasource; import de.thorstenweiskopf.lpm.database.TimeTableDatasource; import de.thorstenweiskopf.lpm.dialogfragments.DatePickerFragment; import de.thorstenweiskopf.lpm.dialogfragments.TimePickerFragment; import de.thorstenweiskopf.lpm.model.TimeEntry; import de.thorstenweiskopf.lpm.R; import android.support.v4.app.FragmentActivity; //Fragmentactivity weil neu mit FragmentDialogen gearbeitet werdeb muss public class TimeManager extends FragmentActivity { //Buttons für Datum und Zeit private Button btnChangeTime, btnChangeDate; //Datum und Zeit Objekte //Kalender Objekt wird erzeugt und geändert vom Time und Datepicker bei Änderungen Calendar calendar = Calendar.getInstance(); final SimpleDateFormat date_format = new SimpleDateFormat("dd.MM.yyyy"); final SimpleDateFormat time_format = new SimpleDateFormat("HH:mm"); final SimpleDateFormat datetime_format = new SimpleDateFormat("dd.MM.yyyy HH:mm"); //Projektdaten private String projectname; private long projectid; private float workingtime_frompj; //DB Schnittstelle private TimeTableDatasource datasource; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_time_manager_view);
  • 56. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 56 //get the datasourceobject needed datasource = new TimeTableDatasource(this); setTimeOnView(calendar); setDateOnView(calendar); addTimeandDateButtonListners(); } /* * (non-Javadoc) * @see android.support.v4.app.FragmentActivity#onStart() * Wird die App hier in den Hintergrund gelegt bleibt aber aktiv * und kommt wieder in den Vordergrund so wird diese Methode ausgeführt * Sie holt sich das aktuelle Projekt und Zeigt die Zeit an da Diese Daten mitlerweile * nicht mehr in der View gespeichert sind. //onStart() in onResume() geändert */ @Override protected void onResume() { super.onStart(); getProject(); showWorkingTime(); } /* * Hildmethode: Errechnet die Arbeitszeit des Projektes wenn möglich * und Schreibt sie in die Datenbank. In die ProjekteTabelle. * Wird nach jedem ein uns ausbuchen ausgeführt. */ private boolean CalcWorkingTime(){ //Get the bookings, show 0 if no bookings are available List<TimeEntry> entrys = new ArrayList<TimeEntry>(); long worktime =0; try { datasource.open(); entrys = datasource.getAllTimeEntrysFromProject(String.valueOf(projectid)); } catch (Exception ex) { Toast.makeText(this, ex.toString(), Toast.LENGTH_LONG).show(); } if (entrys ==null | entrys.isEmpty()){ //Do NOTHING return false; } else { //Read the in and outs List <TimeEntry> in_entrys = new ArrayList<TimeEntry>(); List <TimeEntry> out_entrys = new ArrayList<TimeEntry>(); for (int i=0; i< entrys.size();i++ ){ if (entrys.get(i).getEntrytype() == 0){ in_entrys.add(entrys.get(i)); } else if (entrys.get(i).getEntrytype() == 1){ out_entrys.add(entrys.get(i)); } } //check if as many ins as outs if (in_entrys.size() == out_entrys.size()){ for (int i=0; i< in_entrys.size();i++ ){
  • 57. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 57 long checkout = out_entrys.get(i).getDatetime() ; long checkin = in_entrys.get(i).getDatetime(); worktime += (checkout-checkin )/1000/60; //Store in DB ProjectDatasource pd = new ProjectDatasource(this); pd.open(); pd.updateTime(projectid, worktime); pd.close(); } return true; } else { if (in_entrys.size() > out_entrys.size()){ TimeEntry lastTimeEntry = in_entrys.get(in_entrys.size()-1); long time = lastTimeEntry.getDatetime(); Calendar c = Calendar.getInstance(); c.setTimeInMillis(time); Toast.makeText(this, "Last checkin (" +datetime_format.format(c.getTime())+") without checkout.", Toast.LENGTH_LONG).show(); return false; } else { TimeEntry lastTimeEntry = out_entrys.get(out_entrys.size()- 1); long time = lastTimeEntry.getDatetime(); Calendar c = Calendar.getInstance(); c.setTimeInMillis(time); Toast.makeText(this, "Last checkout (" +datetime_format.format(c.getTime()) +") without checkin.", Toast.LENGTH_LONG).show(); return false; } } } } /* * Hilfmethode holt Arbeitszeit aus der ProjekteDB und zeigt sie an. */ private void showWorkingTime() { String str_hours = "00"; String str_minutes = "00"; TextView tv = (TextView)findViewById(R.id.Text_ProjectTime); ProjectDatasource pd = new ProjectDatasource(this); pd.open(); workingtime_frompj = pd.getWorkingtime(projectid); pd.close(); int h = (int) workingtime_frompj/60; int minuten = (int)workingtime_frompj % 60; if (h < 10){ str_hours = "0"+h; } if (minuten < 10){ str_minutes = "0"+minuten; } tv.setText("Workingtime in hours: " +str_hours+":"+str_minutes); }
  • 58. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 58 /* * Hilfsmethode: Setzt die Listner auf alle Buttons * und führt jeweilige Hilfsfunktion aus */ private void addTimeandDateButtonListners() { findViewById(R.id.button_date).setOnClickListener(new OnClickListener() { public void onClick(View v) { showDatePicker(); } }); findViewById(R.id.button_time).setOnClickListener(new OnClickListener() { public void onClick(View v) { showTimePicker(); } }); findViewById(R.id.button_checkin).setOnClickListener(new OnClickListener() { public void onClick(View v) { checkin(); } }); findViewById(R.id.button_checkout).setOnClickListener(new OnClickListener() { public void onClick(View v) { checkout(); } }); findViewById(R.id.button_hours).setOnClickListener(new OnClickListener() { public void onClick(View v) { justbookthetime(); } }); } /* * Hilfsmethode bucht eingestelle Zeit als Stunde und Minute * vom Calender Objetk */ public void justbookthetime(){ int hour = calendar.get(Calendar.HOUR); int minutes = calendar.get(Calendar.MINUTE); int time = hour*60+minutes; //Store in DB ProjectDatasource pd = new ProjectDatasource(this); pd.open(); long wtime= pd.getWorkingtime(projectid); wtime = time +wtime; pd.updateTime(projectid, wtime); pd.close(); Toast.makeText(this, "timebooking done", Toast.LENGTH_LONG).show(); showWorkingTime(); } /* * Hilfsmethode mach Einträge in die TimeTable */ public void checkin(){ long time = calendar.getTimeInMillis(); try {
  • 59. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 59 datasource.open(); datasource.creatTimeEntry(time, Long.toString(projectid),0);//0 for in datasource.close(); Toast.makeText(this, "checkin done", Toast.LENGTH_LONG).show(); boolean newWorkingTime = CalcWorkingTime(); if (newWorkingTime){ showWorkingTime(); } } catch (Exception ex){ Toast.makeText(this, ex.toString(), Toast.LENGTH_LONG) .show(); } } /* * Hilfsmethode macht Einträge in die TimeTable */ public void checkout(){ long time = calendar.getTimeInMillis(); try { datasource.open(); datasource.creatTimeEntry(time, Long.toString(projectid),1);//1 for out datasource.close(); Toast.makeText(this, "checkout done", Toast.LENGTH_LONG).show(); boolean newWorkingTime = CalcWorkingTime(); if (newWorkingTime){ showWorkingTime(); } } catch (Exception ex){ Toast.makeText(this, ex.toString(), Toast.LENGTH_LONG) .show(); } } /* * Hilfmethode öffnet DatePicker mit aktuellem Datum */ private void showDatePicker() { DatePickerFragment date = new DatePickerFragment(); /** * Set Up Current Date Into dialog */ Calendar calender = Calendar.getInstance(); Bundle args = new Bundle(); args.putInt("year", calender.get(Calendar.YEAR)); args.putInt("month", calender.get(Calendar.MONTH)); args.putInt("day", calender.get(Calendar.DAY_OF_MONTH)); date.setArguments(args); /** * setze die RückkehrMethode wenn Datum ausgewählt wurde */ date.setCallBack(ondate); date.show(getSupportFragmentManager(), "Date Picker"); } /* * Rückkehrmethode: Datum wurde ausgewählt vom Picker
  • 60. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 60 * setze Neue Daten im Calender und Zeige es an */ public OnDateSetListener ondate = new OnDateSetListener() { public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { calendar.set(year, monthOfYear, dayOfMonth); setDateOnView(calendar); } }; /* * Helpermethod opens Timepicker and set current time */ private void showTimePicker() { TimePickerFragment timepicker = new TimePickerFragment(); /** * Set Up Current Date Into dialog */ Calendar calender = Calendar.getInstance(); Bundle args = new Bundle(); args.putInt("minute", calender.get(Calendar.MINUTE)); args.putInt("hour", calender.get(Calendar.HOUR_OF_DAY)); timepicker.setArguments(args); /** * Set Call back to capture selected date */ timepicker.setOnCallBack(ontime); timepicker.show(getSupportFragmentManager(), "Date Picker"); } /* * Helpermethod: Time was choosen from picker */ public OnTimeSetListener ontime = new OnTimeSetListener() { public void onTimeSet(TimePicker view, int hour, int minute) { calendar.set(Calendar.HOUR_OF_DAY, hour); calendar.set(Calendar.MINUTE, minute); setTimeOnView(calendar); } }; /* * (non-Javadoc) * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu) * OptionsMenuStuff: Gibt es hier nicht! */ @Override public boolean onCreateOptionsMenu(Menu menu) { //getMenuInflater().inflate(R.menu.activity_time_manager, menu); return true; } /* * Hilfsmethode holt sich vom Intent die Werte * und Erzeugt das Projekt und Zeigt den Namen in View an */ public void getProject(){ //Lable anzeigen Bundle extras = getIntent().getExtras();
  • 61. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 61 if (extras == null) { return; } // Get data via the key projectname = extras.getString("ProjectName"); projectid = extras.getLong("ProjectId"); workingtime_frompj = extras.getLong("workingtime"); if (projectname != null) { // Show projectname as lable TextView lable = (TextView) findViewById(R.id.Text_ProjectLable); lable.setText(projectname); } } /* * Hilfsfunktion zeigt Zeit im Button */ public void setTimeOnView(Calendar c){ Button time = (Button) findViewById(R.id.button_time); time.setText("Uhrzeit: "+time_format.format(c.getTime())); } /* * Hilfsfunktion zeigt Datum im Button */ public void setDateOnView(Calendar c){ Button date = (Button) findViewById(R.id.button_date); date.setText("Datum: "+date_format.format(c.getTime())); } }
  • 62. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 62 MySQLiteHelper.java package de.thorstenweiskopf.lpm.database; import de.thorstenweiskopf.lpm.database.tables.ProjectTable; import de.thorstenweiskopf.lpm.database.tables.TimeTable; import de.thorstenweiskopf.lpm.database.tables.TodoTable; import android.annotation.TargetApi; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; @TargetApi(11) public class MySQLiteHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = "LittleProjectManager.db"; private static final int DATABASE_VERSION= 1; /* * Datenbank wird erstellt wenn * sie noch nicht existiert mit diesem Namen */ @TargetApi(11) public MySQLiteHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } /* * (non-Javadoc) * @see android.database.sqlite.SQLiteOpenHelper#onCreate(android.database.sqlite.SQLiteDatabase) * Wird automatisch aufgerufen wenn DB noch nicht existiert * Es Werden alle benötigten Tabellen erstellt */ @Override public void onCreate(SQLiteDatabase db) { ProjectTable.onCreate(db); TodoTable.onCreate(db); TimeTable.onCreate(db); } /* * (non-Javadoc) * @see android.database.sqlite.SQLiteOpenHelper#onUpgrade(android.database.sqlite.SQLiteDatabase, int, int) * wird ausgeführt wen DB Version sich im Code ändert */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { TodoTable.onUpgrade(db, oldVersion, newVersion); } }
  • 63. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 63 ProjectDatasource.java /* * Klasse ist das DAO (Database Access Object) * Erlaubt den Zugriff auf die Datenbank und bietet Methoden * für das Abholen und Schreiben von Daten. */ package de.thorstenweiskopf.lpm.database; import java.util.ArrayList; import java.util.List; import de.thorstenweiskopf.lpm.database.tables.ProjectTable; import de.thorstenweiskopf.lpm.database.tables.TodoTable; import de.thorstenweiskopf.lpm.model.Project; import de.thorstenweiskopf.lpm.model.ToDo; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; public class ProjectDatasource { private SQLiteDatabase db; private MySQLiteHelper dbhelper; private String[] allCollums = {ProjectTable.COLUMN_ID, ProjectTable.COLUM_NAME, ProjectTable.COLUM_WORKTIME}; public ProjectDatasource(Context context) { dbhelper = new MySQLiteHelper(context); } /* * Öffnet DB Verbindung */ public void open() throws SQLException { db = dbhelper.getWritableDatabase(); } /* * Schließt DB Verbindung */ public void close() { db.close(); } /* * Erstellt Projekt in der Datenbank * @param name Projektname * @return Project */ public Project creatProject(String name){ ContentValues values = new ContentValues();
  • 64. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 64 values.put(ProjectTable.COLUM_NAME, name); values.put(ProjectTable.COLUM_WORKTIME, 0); long insertId = db.insert(ProjectTable.TABLE_PJ, null, values); Cursor cursor = db.query(ProjectTable.TABLE_PJ, allCollums, TodoTable.COLUMN_ID+" = " +insertId, null, null, null, null); cursor.moveToFirst(); return makeProjectFromCursor(cursor); } /* * Entfernt Proket aus der Datenbank * @param pj Projekt welches entfernt werden soll */ public void removeProject(Project pj){ long id = pj.getId(); System.out.println("Comment deleted with id: " + id); db.delete(ProjectTable.TABLE_PJ, ProjectTable.COLUMN_ID + " = " + id, null); } /* * Gibt Liste aller Projekte zurück * @return ArrayList<Project> */ public List<Project> getAllProjects(){ List<Project> projectlist = new ArrayList<Project>(); Cursor cursor = db.query(ProjectTable.TABLE_PJ, allCollums, null, null, null, null, null); cursor.moveToFirst(); if (cursor.getCount() == 0){ return projectlist; } while (cursor.isAfterLast() == false){ Project pj = makeProjectFromCursor(cursor); projectlist.add(pj); cursor.moveToNext(); } cursor.close(); return projectlist; } /* * Hilfmethode: Macht aus dem cursor(dbeintrag) ein neues Projekt * @param cursor: Db cursor * @return Project */ private Project makeProjectFromCursor(Cursor cursor) { Project pj = new Project(); pj.setId(cursor.getLong(0));
  • 65. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 65 pj.setName(cursor.getString(1)); pj.setTime(cursor.getLong(2)); return pj; } /* * Trägt gesamte bisherige Arbeitszeit in die Tabelle ein * @param projectid: Id des Projektes * @param workingtime: arbeitszeit welche fürs Projekt in die DB soll */ public void updateTime(long projectid, long workingtime) { ContentValues updateTime = new ContentValues(); updateTime.put(ProjectTable.COLUM_WORKTIME, Long.toString(workingtime)); db.update(ProjectTable.TABLE_PJ, updateTime, ProjectTable.COLUMN_ID+"=?", new String[] {Long.toString(projectid)}); } /* * Gibt die Arbeitszeit zurück * @param projectid: Id des Projektes * @return Arbeitszeit */ public long getWorkingtime(long projectid) { Cursor cursor = db.query(ProjectTable.TABLE_PJ, new String[] {ProjectTable.COLUM_WORKTIME}, ProjectTable.COLUMN_ID+"=?", new String[]{Long.toString(projectid)}, null, null, null); cursor.moveToFirst(); return cursor.getLong(0); } }
  • 66. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 66 TimeTableDatasource.java /* * Klasse ist das DAO (Database Access Object) * Erlaubt den Zugriff auf die Datenbank und bietet Methoden * für das Abholen und Schreiben von Daten. */ package de.thorstenweiskopf.lpm.database; import java.util.ArrayList; import java.util.List; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import de.thorstenweiskopf.lpm.database.tables.TimeTable; import de.thorstenweiskopf.lpm.model.TimeEntry; public class TimeTableDatasource { private SQLiteDatabase db; private MySQLiteHelper dbhelper; private String[] allCollums = {TimeTable.COLUMN_ID,TimeTable.COLUM_DATETIME, TimeTable.COLUM_PJ_ID, TimeTable.COLUM_ENTRYTYPE}; public TimeTableDatasource(Context context) { dbhelper = new MySQLiteHelper(context); } /* * Öffnet DB Verbindung */ public void open() throws SQLException { db = dbhelper.getWritableDatabase(); } /* * Schließt DB Verbindung */ public void close() { db.close(); } /* * Erstellt TimeEntry in der Datenbank * @param timeinms Zeit in Millisekunden * @param pjid Projektid des betreffenden Projektes * @param inOrOut 0 für einbuchen, 1 für ausbuchen * @return TimeEntry Objekt */ public TimeEntry creatTimeEntry(long timeinms, String pjid, int inOrOut){ ContentValues values = new ContentValues(); values.put(TimeTable.COLUM_DATETIME, timeinms);
  • 67. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 67 values.put(TimeTable.COLUM_PJ_ID, pjid); values.put(TimeTable.COLUM_ENTRYTYPE, inOrOut); //in DB eintragen long insertId = db.insert(TimeTable.TABLE_TIMETABLE, null, values); //Eintrag holen Cursor cursor = db.query(TimeTable.TABLE_TIMETABLE, allCollums, TimeTable.COLUMN_ID+" = " +insertId, null, null, null, null); cursor.moveToFirst(); return makeTimeEntryFromCursor(cursor); } /* * Entfernt TimeEntry aus der Datenbank * @param te TimeEntry welches entfernt werden soll */ public void removeTimeEntry(TimeEntry te){ long id = te.getId(); System.out.println("Comment deleted with id: " + id); db.delete(TimeTable.TABLE_TIMETABLE, TimeTable.COLUMN_ID + " = " + id, null); } /* * Gibt Liste aller TimeEntry aus DB zurück * @return ArrayList<TimeEntry> */ public List<TimeEntry> getAllTimeEntrys(){ List<TimeEntry> timeentrys = new ArrayList<TimeEntry>(); Cursor cursor = db.query(TimeTable.TABLE_TIMETABLE, allCollums, null, null, null, null, null); cursor.moveToFirst(); if (cursor.getCount() == 0){ return timeentrys; } while (cursor.isAfterLast() == false){ TimeEntry entry = makeTimeEntryFromCursor(cursor); timeentrys.add(entry); cursor.moveToNext(); } cursor.close(); return timeentrys; } /* * Hilfmethode: Macht aus dem cursor(dbeintrag) ein neues TimeEntry * @param cursor: Db cursor * @return TimeEntry */ private TimeEntry makeTimeEntryFromCursor(Cursor cursor) { TimeEntry timeentry = new TimeEntry(); timeentry.setId(cursor.getLong(0)); timeentry.setDatetime(cursor.getLong(1));
  • 68. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 68 timeentry.setPj_id(cursor.getLong(2)); timeentry.setEntrytype(cursor.getLong(3)); return timeentry; } /* * Gibt Liste aller TimeEntry aus DB abhängig vom Projekt zurück * @param projectid * @return ArrayList<TimeEntry> */ public List<TimeEntry> getAllTimeEntrysFromProject(String projectid) { List<TimeEntry> timeentrys = new ArrayList<TimeEntry>(); Cursor cursor = db.query(TimeTable.TABLE_TIMETABLE, allCollums, TimeTable.COLUM_PJ_ID +" = "+projectid, null, null, null, null); cursor.moveToFirst(); if (cursor.getCount() == 0){ return timeentrys; } while (cursor.isAfterLast() == false){ TimeEntry entry = makeTimeEntryFromCursor(cursor); timeentrys.add(entry); cursor.moveToNext(); } cursor.close(); return timeentrys; } }
  • 69. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 69 TodosDatasource.java package de.thorstenweiskopf.lpm.database; import java.util.ArrayList; import java.util.List; import de.thorstenweiskopf.lpm.database.tables.TodoTable; import de.thorstenweiskopf.lpm.model.ToDo; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; public class TodosDatasource { private SQLiteDatabase db; private MySQLiteHelper dbhelper; private String[] allCollums = {TodoTable.COLUMN_ID,TodoTable.COLUM_TODO, TodoTable.COLUM_PJ_ID}; public TodosDatasource(Context context) { dbhelper = new MySQLiteHelper(context); } /* * Öffnet DB Verbindung */ public void open() throws SQLException { db = dbhelper.getWritableDatabase(); } /* * Schließt DB Verbindung */ public void close() { db.close(); } /* * Trägt ToDo in die Tabelle ein * @param projectid: Id des Projektes als Fremdschlüssel * @param todo: ToDo selbst als String * @return ToDo Objekt welches eingetragen wurde */ public ToDo creatTodo(String todo, String pjid){ ContentValues values = new ContentValues(); values.put(TodoTable.COLUM_TODO, todo); values.put(TodoTable.COLUM_PJ_ID, pjid); //in DB eintragen long insertId = db.insert(TodoTable.TABLE_TODO, null, values); //Eintrag holen Cursor cursor = db.query(TodoTable.TABLE_TODO, allCollums, TodoTable.COLUMN_ID+" = " +insertId, null, null, null, null); cursor.moveToFirst();
  • 70. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 70 return makeTodoFromCursor(cursor); } /* * Entfernt ToDo aus der Datenbank * @param todo ToDo welches entfernt werden soll */ public void removeTodo(ToDo todo){ long id = todo.getId(); System.out.println("Comment deleted with id: " + id); db.delete(TodoTable.TABLE_TODO, TodoTable.COLUMN_ID + " = " + id, null); } /* * Gibt Liste aller ToDos zurück * @return ArrayList<ToDo> */ public List<ToDo> getAllTodos(){ List<ToDo> todolist = new ArrayList<ToDo>(); Cursor cursor = db.query(TodoTable.TABLE_TODO, allCollums, null, null, null, null, null); cursor.moveToFirst(); if (cursor.getCount() == 0){ return todolist; } while (cursor.isAfterLast() == false){ ToDo todo = makeTodoFromCursor(cursor); todolist.add(todo); cursor.moveToNext(); } cursor.close(); return todolist; } /* * Hilfmethode: Macht aus dem cursor(dbeintrag) ein neues ToDo * @param cursor: Db cursor * @return ToDo */ private ToDo makeTodoFromCursor(Cursor cursor) { ToDo todo = new ToDo(); todo.setId(cursor.getLong(0)); todo.setTodo(cursor.getString(1)); todo.setPj_id(cursor.getLong(2)); return todo; } /* * Gibt Liste aller ToDo aus DB abhängig vom Projekt zurück
  • 71. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 71 * @param projectid * @return ArrayList<ToDo> */ public List<ToDo> getAllTodosFromProject(String projectid) { List<ToDo> todolist = new ArrayList<ToDo>(); Cursor cursor = db.query(TodoTable.TABLE_TODO, allCollums, TodoTable.COLUM_PJ_ID +" = "+projectid, null, null, null, null); cursor.moveToFirst(); if (cursor.getCount() == 0){ return todolist; } while (cursor.isAfterLast() == false){ ToDo todo = makeTodoFromCursor(cursor); todolist.add(todo); cursor.moveToNext(); } cursor.close(); return todolist; } }
  • 72. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 72 ProjectTable.java /* * Klasse stellt die Tabelle myprojects dar * in der Datenbank gespeichert wird */ package de.thorstenweiskopf.lpm.database.tables; import de.thorstenweiskopf.lpm.database.MySQLiteHelper; import android.database.sqlite.SQLiteDatabase; import android.util.Log; public class ProjectTable { // Database table public static final String TABLE_PJ = "myprojects"; public static final String COLUMN_ID = "_id"; public static final String COLUM_NAME = "name"; public static final String COLUM_WORKTIME = "worktime"; //SQL CREATE Statement private static final String TABLE_CREATE_MYPROJECTS ="" +"create table " +TABLE_PJ +" ( " +COLUMN_ID+ " integer primary key autoincrement, " +COLUM_NAME +" text not null, " +COLUM_WORKTIME +" integer" +");"; /* * Tabelle erstellen */ public static void onCreate(SQLiteDatabase db) { db.execSQL(TABLE_CREATE_MYPROJECTS); } /* * Tabelle Upgraden */ public static void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.w(MySQLiteHelper.class.getName(), "Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data"); db.execSQL("DROP TABLE IF EXISTS " + TABLE_PJ); onCreate(db); } }
  • 73. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 73 TimeTable.java /* * Klasse stellt die Tabelle timetable dar * in der Datenbank gespeichert wird */ package de.thorstenweiskopf.lpm.database.tables; import android.database.sqlite.SQLiteDatabase; import android.util.Log; import de.thorstenweiskopf.lpm.database.MySQLiteHelper; public class TimeTable { // Database table public static final String TABLE_TIMETABLE = "timetable"; public static final String COLUMN_ID = "_id"; public static final String COLUM_DATETIME = "datetime"; public static final String COLUM_PJ_ID = "pj_id"; public static final String COLUM_ENTRYTYPE = "entrytype"; //SQL CREATE Statement private static final String TABLE_CREATE_TIMETABLE ="" +"create table " +TABLE_TIMETABLE +" ( " +COLUMN_ID+ " integer primary key autoincrement, " +COLUM_DATETIME +" integer not null, " +COLUM_PJ_ID + " integer, " +COLUM_ENTRYTYPE + " integer not null," + " FOREIGN KEY ("+COLUM_PJ_ID+") REFERENCES "+ProjectTable.TABLE_PJ+" ("+ProjectTable.COLUMN_ID+")" +");"; /* * Tabelle erstellen */ public static void onCreate(SQLiteDatabase db) { db.execSQL(TABLE_CREATE_TIMETABLE); } /* * Tabelle Upgraden */ public static void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.w(MySQLiteHelper.class.getName(), "Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data"); db.execSQL("DROP TABLE IF EXISTS " + TABLE_TIMETABLE); onCreate(db); } }
  • 74. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 74 TodoTable.java /* * Klasse stellt die Tabelle mytodos dar * in der Datenbank gespeichert wird */ package de.thorstenweiskopf.lpm.database.tables; import de.thorstenweiskopf.lpm.database.MySQLiteHelper; import android.annotation.TargetApi; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.util.Log; public class TodoTable { // Database table public static final String TABLE_TODO = "mytodos"; public static final String COLUMN_ID = "_id"; public static final String COLUM_TODO = "todo"; public static final String COLUM_PJ_ID = "pj_id"; //SQL CREATE Statement private static final String TABLE_CREATE_MYTODOS ="" +"create table " +TABLE_TODO +" ( " +COLUMN_ID+ " integer primary key autoincrement, " +COLUM_TODO +" text not null, " +COLUM_PJ_ID + " integer," + " FOREIGN KEY ("+COLUM_PJ_ID+") REFERENCES "+ProjectTable.TABLE_PJ+" ("+ProjectTable.COLUMN_ID+")" +");"; /* * Tabelle erstellen */ public static void onCreate(SQLiteDatabase db) { db.execSQL(TABLE_CREATE_MYTODOS); } /* * Tabelle Upgraden */ public static void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.w(MySQLiteHelper.class.getName(), "Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data"); db.execSQL("DROP TABLE IF EXISTS " + TABLE_TODO); onCreate(db); } }
  • 75. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 75 DatePickerFragment.java /* * Klasse muss als sogenantes DatePickerFragment geschrieben werden * welche Ihrerseits bei der Erzeugung einen DatePickerDialog öffnet * Den Rest übernimmt dann Das Framework bzw. die Activity welches * diese Klasse mit Argumenten füttert und Ausführen lässt */ package de.thorstenweiskopf.lpm.dialogfragments; import android.app.DatePickerDialog; import android.app.DatePickerDialog.OnDateSetListener; import android.app.Dialog; import android.os.Bundle; import android.support.v4.app.DialogFragment; public class DatePickerFragment extends DialogFragment { //Klassenvariablen private int year, month, day; OnDateSetListener ondateSet; public DatePickerFragment() { } public void setCallBack(OnDateSetListener ondate) { ondateSet = ondate; } /* * (non-Javadoc) * * @see android.support.v4.app.Fragment#setArguments(android.os.Bundle) * Methode um Daten zu setzen */ @Override public void setArguments(Bundle args) { super.setArguments(args); year = args.getInt("year"); month = args.getInt("month"); day = args.getInt("day"); } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { return new DatePickerDialog(getActivity(), ondateSet, year, month, day); } }
  • 76. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 76 TimePickerFragment.java /* * Klasse muss als sogenantes TimePickerFragement geschrieben werden * welche Ihrerseits bei der Erzeugung einen TimePickerDialog öffnet * Den Rest übernimmt dann Das Framework bzw. die Activity welches * diese Klasse mit Argumenten füttert und Ausführen lässt */ package de.thorstenweiskopf.lpm.dialogfragments; import android.app.Dialog; import android.app.TimePickerDialog; import android.app.TimePickerDialog.OnTimeSetListener; import android.os.Bundle; import android.support.v4.app.DialogFragment; public class TimePickerFragment extends DialogFragment { //Klassen variablen private int hour, minute; OnTimeSetListener ontimeset; public TimePickerFragment() { } public void setOnCallBack (OnTimeSetListener ontime){ ontimeset = ontime; } /* * (non-Javadoc) * @see android.support.v4.app.Fragment#setArguments(android.os.Bundle) * Methode um Daten zu setzen */ @Override public void setArguments(Bundle args) { super.setArguments(args); hour = args.getInt("hour"); minute = args.getInt("minute"); } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { return new TimePickerDialog(getActivity(), ontimeset, hour, minute, true); } }
  • 77. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 77 TimeEntry.java /* * Klasse stellt ein TimeEntry dar wie es * in der Datenbank gespeichert wird */ package de.thorstenweiskopf.lpm.model; public class TimeEntry { private long datetime; private int entrytype; //0 in 1 out private long id; private long pj_id; public long getDatetime() { return datetime; } public void setDatetime(long datetime) { this.datetime = datetime; } public int getEntrytype() { return entrytype; } public void setEntrytype(long entrytype) { this.entrytype = (int) entrytype; } public long getId() { return id; } public void setId(long id) { this.id = id; } public long getPj_id() { return pj_id; } public void setPj_id(long pj_id) { this.pj_id = pj_id; } }
  • 78. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 78 ToDo.java /* * Klasse stellt ein ToDo dar wie es * in der Datenbank gespeichert wird */ package de.thorstenweiskopf.lpm.model; public class ToDo { private String todo; private long id; private long pj_id; public String getTodo() { return todo; } public void setTodo(String todo) { this.todo = todo; } public long getId() { return id; } public void setId(long id) { this.id = id; } public long getPj_id() { return pj_id; } public void setPj_id(long pj_id) { this.pj_id = pj_id; } //Rückgabewert des Objektes für die Liste public String toString(){ return todo; } }
  • 79. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 79 R.java /* AUTO-GENERATED FILE. DO NOT MODIFY. * * This class was automatically generated by the * aapt tool from the resource data it found. It * should not be modified by hand. */ package de.thorstenweiskopf.lpm; public final class R { public static final class attr { } public static final class drawable { public static final int ic_action_search=0x7f020000; public static final int ic_launcher=0x7f020001; } public static final class id { public static final int Add=0x7f07000f; public static final int Remove=0x7f070010; public static final int Text_ProjectLable=0x7f070001; public static final int Text_ProjectTime=0x7f070002; public static final int addpj=0x7f07000b; public static final int button1=0x7f07000a; public static final int button_checkin=0x7f070005; public static final int button_checkout=0x7f070006; public static final int button_date=0x7f070003; public static final int button_hours=0x7f070007; public static final int button_time=0x7f070004; public static final int editText1=0x7f070009; public static final int listView1=0x7f070000; public static final int removepj=0x7f07000d; public static final int showTodos=0x7f07000c; public static final int timemanager=0x7f07000e; public static final int todo_lable=0x7f070008; } public static final class layout { public static final int activity_project_view=0x7f030000; public static final int activity_time_manager_view=0x7f030001; public static final int activity_todos_view=0x7f030002; public static final int additem=0x7f030003; } public static final class menu { public static final int activity_project_view=0x7f060000; public static final int activity_todos_view=0x7f060001; } public static final class string { public static final int Add=0x7f040002; public static final int Remove=0x7f040003; public static final int app_name=0x7f040000; public static final int menu_addpj=0x7f040008; public static final int menu_remove_pj=0x7f04000a; public static final int menu_settings=0x7f040007; public static final int menu_showtodos=0x7f040009; public static final int menu_timemanager=0x7f04000b; public static final int menu_timestats=0x7f04000c; public static final int time_checkinbutton=0x7f04000d; public static final int time_checkoutbutton=0x7f04000e;
  • 80. 10. Januar 2013 APPLIKATIONSENTWICKLUNG FÜR ANDROID 80 public static final int time_hourbutton=0x7f04000f; public static final int title_activity_my_todo_add=0x7f040004; public static final int title_activity_my_todos_overview=0x7f040001; public static final int title_activity_project_view=0x7f040005; public static final int title_activity_time_manager=0x7f040006; } public static final class style { public static final int AppTheme=0x7f050000; } }