This website uses cookies for visitor traffic analysis. By using the website, you agree with storing the cookies on your computer.More information

Creating an Android App using JVx AddOns

Documents for the development of and with JVx.

Creating an Android App using JVx AddOns

Postby Development@SIB » Fri Sep 17, 2010 1:30 pm

The Android SDK already offers everything that is necessary to create a visually attractive application. The GUI components work well and can, through the integration in Eclipse, also be used with a WYSIWYG editor. Here JVx therefore does not have to simplify things even more.

However, when we try to create a database application, we quickly approach SDK´s limits. This is where JVx comes into play. JVx offers session management, access to external data (which does not necessarily have to a database) and, more importantly, the business logic of existing client applications can be used without adaptation.

No web services have to be created, and no separate framework is necessary.

Requirements

This example assumes that:

  • Eclipse WTP Edition is used
  • A current version of Apache Tomcat is installed and available as a server environment in Eclipse
  • Android SDK and the Eclipse plugin are installed and configured

Example

We will use our First JVx Application as a base for an Android App. The application visualizes the data from a simple table in our database. Our App offers a login as well as the display of the data.

We create and configure our Android App:

  1. Create a new Android project (Application: FirstAndroid, Package: apps.firstandroid, Activity: Login)
  2. Define the project JVx as dependency (Java Build Path / Projects)
  3. Add the src directory of our AddOns project as source directory per Link (Project Path / Source)
  4. Derive our login activity from com.sibvisions.android.RemoteActivity

The directory Link is required, since otherwise the JVx AddOns are installed as standalone applications.


We now create the layout for our 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>

In addition, strings.xml (directory res/values) is amended as follows:

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>

The source code for our activity is modified as follows:

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

AndroidManifest.XML is replaced by:

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>

In contrast to the standard file, the remote application is configured as an application class. This gives all activities access to the connection. In addition, the INTERNET permission was granted to allow communication with the server.


For the first launch of the App we also need an appropriate server to provide the business logic.
The line

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

shows that a connection to a web/application server (e.g. Tomcat) is made. This allows access to the business logic of the application. The IP 10.0.2.2 is interpreted by the emulator as localhost!

The following steps are required to configure the server:

  1. Create a new Dynamic Web Project for the Tomcat Runtime Environment (standard settings)
  2. Define the projects JVx and JVxFirstApp as dependencies (Java Build Path / Projects)
  3. Define both dependencies as Java EE Module dependencies
  4. Define the JDBC driver for the HSQLDB as Java EE module dependency (Add jar / JVxFirstApp/libs/server/...)
  5. Create a directory link in the directory WebContent/WEB-INF using the name rad, for the rad directory from the JVxFirstApp directory structure, e.g.: C:\Tools\eclipse_workspace\JVxFirstApp\trunk\java\rad (it should contain the directories: apps, server)
  6. Add the project to an existing server environment (Context: AndroidServer)
  7. Start the server and test using: http://localhost (HTTP State 405 should be displayed)

The directory link is necessary to find the application configuration (config.xml). There are additional ways to define to configuration, for example, using a Java property during the start of the server. In this case, however, the directory Link should work well.


Now it is time to start our Android App for the first time. Select the project and start it as Android Application (after that we may have to configure a device using the standard settings).

After the emulator was launched, the login activity appears. After entering username and password (admin / admin) "It works" should appear. This means that logging in to the server worked without any problems.

In the next step we want to display the data in the database. For this purpose we create a new activity with the following content:

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

The Layout for the Activity is defined as follows:

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>

Now the Activity is defined in AndroidManifest.xml

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


inally we open the activity after login by replacing (in our Login Activity) the line:

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);


After restarting the App, the following result should be displayed (before and after successful login):

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

Of course the displayed data depends on your database!
User avatar
Development@SIB
 
Posts: 325
Joined: Mon Sep 28, 2009 1:54 pm

Return to Documentation