Erstellen einer Android App mit den JVx AddOns

Dokumente für die Entwicklung von und mit JVx.

Erstellen einer Android App mit den JVx AddOns

Postby Development@SIB » Wed May 26, 2010 2:32 pm

Das Android SDK bringt bereits alles mit was notwendig ist um eine optisch ansprechende Applikation zu erstellen. Die GUI Komponenten funktionieren wunderbar und können durch die Integration in Eclipse auch mit einem WYSIWYG Editor verwendet werden. An dieser Stelle muss JVx also die Dinge nicht noch einfacher machen als sie ohnehin schon sind.

Aber wenn es darum geht eine Datenbank Anwendung zu erstellen, stößt man sehr schnell an die Grenzen des SDK. Und genau an dieser Stelle kommt JVx ins Spiel. Mit JVx erhält man ein zeitgemäßes Session Management, Zugriff auf Daten von Fremdsystemen (das müssen nicht unbedingt Datenbanken sein) und vor allem kann man die Business Logik der vorhandenen Kundenapplikation ohne Anpassung nutzen.

Dafür müssen keine Webservices erstellt werden und ein spezielles Framework ist ebenfalls nicht nötig.

Voraussetzungen

Unser Anwendungsbeispiel setzt voraus:

  • Die Eclipse WTP Edition wird verwendet
  • Ein aktueller Apache Tomcat ist installiert und als Server Umgebung in Eclipse vorhanden
  • Das Android SDK und das Eclipse Plugin sind installiert und konfiguriert

Anwendungsbeispiel

Wir verwenden unsere Erste JVx Applikation als Ausgangsbasis für eine Android App. Die Applikation visualisiert die Daten einer simplen Tabelle aus einer Datenbank. Unsere App bietet einen Login sowie die Anzeige der selben Daten.

Wir erstellen und konfigurieren unsere Android App:

  1. Erstellen eines neuen Android Projektes (Application: FirstAndroid, Package: apps.firstandroid, Activity: Login)
  2. Das Projekt JVx als Abhängigkeit definieren (Java Build Path / Projects)
  3. Das src Verzeichnis unseres AddOns Projekt als beliebiges Source Verzeichnis per Link hinzufügen (Project Path / Source)
  4. Ableitung unserer Login Activity von com.sibvisions.android.RemoteActivity

Der Verzeichnis Link ist nötig da ansonsten die JVx AddOns als eigenständige Applikation installiert werden.


Nun erstellen wir das Layout für unsere Login Activity:

Code: Select all
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="fill_parent"
           android:layout_height="wrap_content">

   <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_gravity="fill_horizontal"
        android:layout_marginLeft="3px"
        android:layout_marginRight="3px"
        android:id="@+id/loginframe" android:visibility="visible">
    
      <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:padding="6dip">
       
        <LinearLayout android:orientation="vertical"
                      android:layout_width="0dip"
                      android:layout_weight="1"
                      android:layout_height="wrap_content">
                     
           <TextView android:layout_width="fill_parent"
                     android:layout_height="wrap_content"
                     android:textSize="8pt"
                     android:typeface="sans"
                     android:textStyle="bold"
                     android:id="@+id/login_welcometitle"
                     android:text="@string/login_welcometitle"></TextView>
           <TextView android:layout_width="fill_parent"
                     android:layout_height="wrap_content"
                     android:textSize="13px"
                     android:paddingLeft="8px"
                     android:id="@+id/login_welcomesubtitle"
                     android:text="@string/login_welcomesubtitle"></TextView>
          
        </LinearLayout>
         
      </LinearLayout>
      <View android:layout_width="fill_parent"
            android:layout_height="1px"
            android:background="#999999"
            android:id="@+id/login_separator"></View>
      
      <TextView android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/login_lblusername"
                android:layout_marginTop="15px"
                android:id="@+id/login_lblusername"></TextView>
      <EditText android:layout_height="wrap_content"
                android:layout_width="fill_parent"
                android:inputType="textShortMessage"
                android:id="@+id/login_username"></EditText>
      
      <TextView android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingTop="5px"
                android:text="@string/login_lblpassword"
                android:id="@+id/login_lblpassword"></TextView>
      <EditText android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:inputType="textPassword"
                android:id="@+id/login_password"></EditText>
      
       <Button android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:layout_marginTop="20px"
               android:text="@string/login_butlogin"
               android:layout_gravity="center_horizontal"
               android:onClick="doLogin"
               android:id="@+id/login_butlogin"
               android:minWidth="110px"></Button>

    </LinearLayout>
      
</FrameLayout>

Zusätzlich ergänzen wir unsere strings.xml (Verzeichnis res/values) um:

Code: Select all
<string name="login_welcometitle">Welcome</string>
<string name="login_welcomesubtitle">Please enter your username and password</string>
<string name="login_lblusername">Username</string>
<string name="login_lblpassword">Password</string>
<string name="login_butlogin">Login</string>

<string name="txt_error">Error</string>
<string name="txt_ok">OK</string>

Der Source Code für unsere Activity ändern wir wie folgt:

Code: Select all
package apps.firstandroid;

import javax.rad.remote.MasterConnection;

import android.os.Bundle;
import android.view.View;
import android.widget.EditText;

import com.sibvisions.android.app.RemoteActivity;
import com.sibvisions.android.app.RemoteApplication;
import com.sibvisions.rad.remote.http.HttpConnection;

public class Login extends RemoteActivity
{
   //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   // Overwritten methods
   //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

   /**
    * {@inheritDoc}
    */
   @Override
   public void onCreate(Bundle pSavedInstanceState)
   {
      super.onCreate(pSavedInstanceState);
      
      setContentView(R.layout.main);
   }
   
   //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   // User-defined methods
   //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

   /**
    * Login button action.
    *
    * @param pView the view
    */
   public void doLogin(View pView)
   {
      try
      {
         HttpConnection conHttp = new HttpConnection(
                                  "http://10.0.2.2/AndroidServer/services/Server");
         
         MasterConnection macon = new MasterConnection(conHttp);
         
         macon.setApplicationName("firstapp");
         macon.setUserName(((EditText)findViewById(R.id.login_username)).
                           getText().toString());
         macon.setPassword(((EditText)findViewById(R.id.login_password)).
                           getText().toString());
         
         macon.open();

         ((RemoteApplication)getApplication()).setConnection(macon);

         showError(R.string.txt_error, R.string.txt_ok, "It works");
      }
      catch (Throwable th)
      {
         showError(R.string.txt_error, R.string.txt_ok, th.getMessage());
      }
   }
   
}   // Login

Das AndroidManifest.XML ersetzen wir mit:

Code: Select all
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="apps.firstandroid"
      android:versionCode="1"
      android:versionName="1.0">
     
    <application android:name="com.sibvisions.android.app.RemoteApplication"
                 android:icon="@drawable/icon"
                 android:label="@string/app_name">
                 
        <activity android:name=".Login"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>

    <uses-permission android:name="android.permission.INTERNET"></uses-permission>
</manifest>

Im Unterschied zur Standard Datei ist die RemoteApplication als Applikationsklasse konfiguriert. Dadurch erhalten alle Activities Zugriff auf die Connection. Zusätzlich wurde die INTERNET Permission erteilt, damit die Kommunikation mit dem Server erlaubt ist.


Für den ersten Start der App benötigen wir noch einen geeigneten Server der die Business Logik bereitstellt. Wie anhand der Zeile

Code: Select all
HttpConnection conHttp = new HttpConnection("http://10.0.2.2/AndroidServer/services/Server");

zu erkennen ist, wird die Verbindung zu einem Web/Applikationsserver (z.B. Tomcat) aufgebaut. Dieser ermöglicht den Zugriff auf die Business Logik der Applikation. Die IP 10.0.2.2 wird vom Emulator als localhost interpretiert!

Um den Server einzurichten sind folgende Schritte nötig:

  1. Erstellen eines neuen Dynamic Web Projektes für die Tomcat Laufzeit Umgebung (Standard Einstellungen)
  2. Die Projekte JVx und JVxFirstApp als Abhängigkeiten definieren (Java Build Path / Projects)
  3. Die beiden Abhängigkeiten zusätzlich als Java EE Module Dependencies definieren
  4. Den JDBC Treiber für die HSQLDB als Java EE Module Dependency definieren (Add jar / JVxFirstApp/libs/server/...)
  5. Erstellen eines Verzeichnis Links im Verzeichnis WebContent/WEB-INF mit dem Namen rad zu dem rad Verzeichnis aus der JVxFirstApp Verzeichnisstrutkur, z.B.: C:\Tools\eclipse_workspace\JVxFirstApp\trunk\java\rad (Darin sollten die Verzeichnisse: apps, server zu finden sein)
  6. Das Projekt zu einer bereits vorhandenen Server Umgebung hinzufügen (Context: AndroidServer)
  7. Den Server starten und testen mit: http://localhost (HTTP Status 405 sollte geliefert werden)

Der Verzeichnis Link wird benötigt damit die Applikationskonfiguration (config.xml) gefunden wird. Es gibt noch weitere Möglichkeiten die Konfiguration zu definieren, z.B. mit einer Java Property beim Start des Servers. Doch an dieser Stelle sind wir mit dem Verzeichnis Link auch gut bedient.


Nun ist es an der Zeit unsere Android App zum ersten Mail zu starten. Dafür selektieren Sie das Projekt und starten es als Android Application (danach ggf. ein Device mit den Standardeinstellungen konfigurieren).

Nachdem der Emulator gestartet wurde erscheint die Login Activity und durch die Eingabe von Benutzernamen und Passwort (admin / admin) sollte "It works" erscheinen. Die Anmeldung an unseren Server hat somit ohne Probleme funktioniert.

Im nächsten Schritt kümmern wir uns um die Darstellung der Daten aus der Datenbank.
Dafür erstellen wir eine neue Activity mit folgendem Inhalt:

Code: Select all
package apps.firstandroid;

import javax.rad.remote.MasterConnection;
import javax.rad.remote.SubConnection;

import android.os.Bundle;
import android.widget.ListView;

import com.sibvisions.android.app.RemoteActivity;
import com.sibvisions.android.app.RemoteApplication;
import com.sibvisions.android.widget.DataBookAdapter;
import com.sibvisions.rad.model.remote.RemoteDataBook;
import com.sibvisions.rad.model.remote.RemoteDataSource;
import com.sibvisions.util.type.CommonUtil;

public class Table extends RemoteActivity
{
   //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   // Overwritten methods
   //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

   /**
    * {@inheritDoc}
    */
   @Override
   public void onCreate(Bundle pSavedInstanceState)
   {
      super.onCreate(pSavedInstanceState);

      setContentView(R.layout.table);

      try
      {
         SubConnection con = ((MasterConnection)((RemoteApplication)getApplication()).
                             getConnection()).
                             createSubConnection("apps.firstapp.frames.DBEdit");
         con.open();
         
         setConnection(con);
         
         RemoteDataSource dataSource = new RemoteDataSource(con);
         dataSource.open();
         
         RemoteDataBook rdbTable = new RemoteDataBook();
         rdbTable.setDataSource(dataSource);
         rdbTable.setName("contacts");
         rdbTable.open();

         rdbTable.getRowDefinition().setTableColumnNames(new String[] {"LASTNAME",
                                                                       "FIRSTNAME"});
         
         DataBookAdapter adapter = new DataBookAdapter(this,
                                                       rdbTable,
                                                  android.R.layout.simple_list_item_2);
         adapter.setColumnViewResources(new int[] {android.R.id.text1,
                                                   android.R.id.text2});
         
         ListView view = (ListView)findViewById(R.id.tablelist);
         view.setAdapter(adapter);
      }
      catch (Throwable th)
      {
         showError(R.string.txt_error, R.string.txt_ok, CommonUtil.dump(th, true));
      }
   }
   
}   // Table

Das Layout für die Activity ist wie folgt definiert:

Code: Select all
<?xml version="1.0" encoding="utf-8"?>
<ListView
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:id="@+id/tablelist">
</ListView>

Nun definieren wir die Activity im AndroidManifest.xml

Code: Select all
...
    ...
    ...
    <activity android:name=".Table"></activity>
</application>


Und abschließend öffnen wir noch die Activity nach erfolgter Anmeldung. Dafür ersetzen wir in unserer Login Activity, die Zeile:

Code: Select all
showError(R.string.txt_error, R.string.txt_ok, "It works");

mit

Code: Select all
Intent intAfterLogin = new Intent(this, Table.class);
startActivity(intAfterLogin);


Nachdem die App neu gestartet wurde, sollte folgendes Ergebnis zu sehen sein (vor und nach erfolgreicher Anmeldung):

firstandroid.gif
firstandroid.gif (18.42 KiB) Viewed 5126 times

Die angezeigten Daten sind natürlich abhängig von ihrer Datenbank!
User avatar
Development@SIB
 
Posts: 311
Joined: Mon Sep 28, 2009 1:54 pm

Return to Dokumentation