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;
}
}
Top Related