Blackberry Development 6: SQLite Database

All in One Test on SQLite DB

The specifications on the SQL syntax used by SQLite can be found in www.sqlite.org.

The following program tests the following operation on a SQLite DB:

  • create a db
  • create a table
  • insert a record
  • update the record
  • query the record
  • delete the record
  • delete the db
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import net.rim.device.api.database.*;
import net.rim.device.api.io.*;
import net.rim.device.api.ui.*;

public class DBTest extends UiApplication
{
    public static void main(String[] args)
    {
        CreateDatabase theApp = new CreateDatabase();
        theApp.enterEventDispatcher();
    }

    public DBTest()
    {
        pushScreen(new DBTestScreen());
    }  
}

class DBTestScreen extends MainScreen
{
    Database d;
    public DBTestScreen()
    {
       LabelField title = new LabelField("SQLite DB Test",
                                          LabelField.ELLIPSIS |
                                          LabelField.USE_ALL_WIDTH);
       setTitle(title);
       add(new RichTextField("Test a database called " +
                             "MyTestDatabase.db on the SDCard."));
       try
       {
           // 1. create a SQLite DB
           URI myURI = URI.create("file:///SDCard/Databases/SQLite_Guide/" +
                                  "MyTestDatabase.db");
           d = DatabaseFactory.create(myURI);
           // 2. Create a table
           // d = DatabaseFactory.openOrCreate(myURI);
           Statement st = d.createStatement( "CREATE TABLE People ( " +
                                              "Name TEXT, " +
                                              "Age INTEGER )" );
           st.prepare();
           st.execute();
           st.close();
           //3 insert a record
           st = d.createStatement("INSERT INTO People(Name,Age) " +
                                             "VALUES ('John',37)");
           st.prepare();
           st.execute();
           st.close();
           //4 query the record
            Statement st = d.createStatement("SELECT Name,Age FROM People");

            st.prepare();
            Cursor c = st.getCursor();

            Row r;
            int i = 0;
            while(c.next())
            {
                r = c.getRow();
                i++;
                add(new RichTextField(i + ". Name = " + r.getString(0) +
                                          " , " +
                                          "Age = " + r.getInteger(1)));
            }
            if (i==0)
            {
                add(new RichTextField("No data in the People table."));
            }
            st.close();
           //5. update the record
           Statement st = d.createStatement("UPDATE People SET Age=38 " +
                                         "WHERE Name='John'");
           st.prepare();
           st.execute();
           st.close();
           //6. delete the record
            Statement st = d.createStatement("DELETE FROM People");
            st.prepare();
            st.execute();
            st.close();
           //7. Finally close the db
           d.close();
           //8. Delete the database
           DatabaseFactory.delete(myURI);
       }
       catch ( Exception e )
       {        
           System.out.println( e.getMessage() );
           e.printStackTrace();
       }
    }
}

Blackberry Development 5: FileConnection APIs

Refer to http://developers.sun.com/mobility/apis/articles/fileconnection/ for the API.

FileConnectionTest.java

package com.henry416.fileconnection;

import net.rim.device.api.ui.UiApplication;

public class FileConnectionTest extends UiApplication {

    public FileConnectionApplication() {
        FileConnectionScreen screen = new FileConnectionScreen();
        pushScreen(screen);
     }

    public static void main(String[] args) {
        FileConnectionTest app = new FileConnectionTest();
        app.enterEventDispatcher();
     }

}

FileConnectionScreen.java

package com.henry416.fileconnection;

import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.ui.component.Menu;
import net.rim.device.api.ui.component.ObjectListField;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.util.StringProvider;

public class FileConnectionScreen extends MainScreen {

    private ObjectListField fileList;
    private String currentPath = "file:///";

     public FileConnectionScreen() {
         setTitle("FileConnection");

        fileList = new ObjectListField();

        fileList.set(new String[] {"store/", "SDCard/"});

        add(fileList);
     }

    protected void makeMenu(Menu menu, int instance) {
        super.makeMenu(menu, instance);
        menu.add(new MenuItem(new StringProvider("Select"), 10, 10) {
            public void run() {
                loadFile();
            }
        });
     }

    private void loadFile() {
        currentPath += fileList.get(fileList, fileList.getSelectedIndex());
        try {
            FileConnection fileConnection = (FileConnection)Connector.open(currentPath);
            if (fileConnection.isDirectory()) {
                Enumeration directoryEnumerator = fileConnection.list();
                Vector contentVector = new Vector();
                while(directoryEnumerator.hasMoreElements()) {

                    contentVector.addElement(directoryEnumerator.nextElement());
                }
                String[] directoryContents = new String[contentVector.size()];
                contentVector.copyInto(directoryContents);

                fileList.set(directoryContents);
            }

        } catch (IOException ex) {

        }
    }
}

For more samples are here.

Blackberry Development 4: Create an User Interface

There are three types of UI components from RIM API:

Screens (net.rim.device.api.ui.Screen): There’s one active screen per application at any time. Screens handle field layout through a delegate manager and provide additional functionality like menus.

Managers (net.rim.device.api.ui.Manager): These arrange fields on the screen. Each field must belong to one and only one manager. Each manager is also a field, meaning managers can contain other managers, allowing for some pretty intricate UI layouts.

Fields (net.rim.device.api.ui.Field): These are the basic building blocks of the UI. Generally, each control, such as a button or text field, corresponds to an instance of a field. The Field class draws the control and handles user input.

Please refer to Blackberry Smartphone UI Guide from RIM.

UiTest.java(Project: UiTest)

package com.henry416.UiTest;
import net.rim.device.api.ui.UiApplication;

public class UiTest extends UiApplication {
     public UiTest () {
        UiTestMainScreen mainScreen = new UiTestMainScreen();
        pushScreen(mainScreen);
     }

     public static void main(String[] args) {
        UiTest app = new UiTest();
        app.enterEventDispatcher();
     }
}

UiTestMainScreen.java:

package com.henry416.UiTest;
import net.rim.device.api.ui
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.component.BitmapField;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.component.EditField;
import net.rim.device.api.ui.component.PasswordEditField;
import net.rim.device.api.ui.component.CheckboxField;
import net.rim.device.api.ui.component.ObjectChoiceField;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.container.HorizontalFieldManager;
import net.rim.device.api.ui.container.HorizontalFieldManager;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.component.Dialog;
public class UiTestMainScreen extends MainScreen implements FieldChangeListener {
    BitmapField bitmapField;
    EditField usernameField;
    PasswordEditField passwordField;
    ObjectChoiceField domainField;
    CheckboxField rememberCheckbox;
    ButtonField clearButton;
    ButtonField loginButton;
    public UiTestMainScreen() {
         // add a logo at top, also put it under rsc folder of the project
         Bitmap logoBitmap = Bitmap.getBitmapResource("UiTest_logo.png");
         bitmapField = new BitmapField(logoBitmap, Field.FIELD_HCENTER);
         add(bitmapField);
         add(new SeparatorField());
         add(new LabelField("Please enter your credentials:"));
         // add two fields
         usernameField = new EditField("Username:", "");
         passwordField = new PasswordEditField("Password:", "");
         add(usernameField);
         add(passwordField);
         // add a domain field
         domainField = new ObjectChoiceField("Domain:", new String[] {"Prod", "Dev"});
         add(domainField);
         // add a checkbox
         rememberCheckbox = new CheckboxField("Remember password", false);
         add(rememberCheckbox);
         add(new SeparatorField());
         // create two buttons
         clearButton = new ButtonField("Clear", ButtonField.CONSUME_CLICK);
         loginButton = new ButtonField("Login", ButtonField.CONSUME_CLICK);
         // using HorizontalFieldManager to add two buttons
         HorizontalFieldManager buttonManager = new HorizontalFieldManager(Field.FIELD_RIGHT);
         buttonManager.add(clearButton);
         buttonManager.add(loginButton);
         add(buttonManager);
         // hook the events
         clearButton.setChangeListener(this);
         loginButton.setChangeListener(this);
    }
    public void fieldChanged(Field field, int context) {
       if (field == clearButton) {
          clearTextFields();
          //Dialog.inform("Clear Button Pressed!");
       }
       else if (field == loginButton) {
            login();
            }
    }
    private void clearTextFields() {
        usernameField.setText("");
        passwordField.setText("");
    }
    private void login() {
         if (usernameField.getTextLength() == 0 || passwordField.getTextLength() == 0) {
            Dialog.alert("You must enter a username and password");
         }
         else {
            String username = usernameField.getText();
            String selectedDomain =
               (String)domainField.getChoice(domainField.getSelectedIndex());
            LoginSuccessScreen loginSuccessScreen =
                new LoginSuccessScreen(username, selectedDomain);
             UiApplication.getUiApplication().pushScreen(loginSuccessScreen);
         }
     }
}

LoginSuccessScreen.java

package com.henry416.UiTest;

import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.container.MainScreen;

public class LoginSuccessScreen extends MainScreen {
    public LoginSuccessScreen(String username, String domain) {
        add(new LabelField("Logged in!"));
        add(new LabelField("Username: " + username));
        add(new LabelField("Domain: " + domain));
    }
}

Blackberry Development 3: Single Threading and Event Testing

The BlackBerry UI API is single threaded. This means that all UI updates and events are handled by the same thread—or more precisely, they must be handled while holding the event lock, which most of the time is held by the UI thread.

First, let’s change labelFieldto be a member variable instead of a variable local to the constructor, and add a method to append text to it:

public class HelloWorldMainScreen extends MainScreen {

    private LabelField labelField;

    public HelloWorldMainScreen() {
        labelField = new LabelField("Hello World");
        add(labelField);
    }

    public void appendLabelText(String text) {
        labelField.setText(labelField.getText() + "\n" + text);
    }

}

Because appendLabelText calls LabelField.setText, the call can only be made from the event thread. If you attempt to call this method directly from another thread, an exception will be thrown.

Now, we’ll define the thread class that will actually do the testing. It will loop from 1 to 10. In each iteration, it will wait 5 seconds and then add some text to the LabelField. Create a new class called MainScreenUpdaterThread that extends java.lang.Thread. The full source code follows:

package com.henry416;

import net.rim.device.api.ui.UiApplication;

public class MainScreenUpdaterThread extends Thread {
    HelloWorldMainScreen mainScreen;

    public MainScreenUpdaterThread(HelloWorldMainScreen mainScreen) {
        this.mainScreen = mainScreen;
    }

    public void run() {
        for (int i = 0; i < 10; i++) {

            try {
                 Thread.sleep(5000);
            } catch (InterruptedException ex) {

            }
            // Queue a new task on the event thread
            UiApplication.getUiApplication().invokeLater(new Runnable() {
                 public void run() {
                    mainScreen.appendLabelText("Testing");
                 }

            });

        }
     }
}

To actually update the UI, we’re using an anonymous inner class, which is a class that we define at the point where we instantiate it. Our anonymous inner class calls the one method that needs to be called on the event thread: appendLabelText (which calls LabelField.setText).

We’ll start our thread in the HelloWorldMainScreen constructor as follows:

    public HelloWorldMainScreen() {
        labelField = new LabelField("Hello World");

        add(labelField);

        MainScreenUpdaterThread thread = new MainScreenUpdaterThread(this);
        thread.start();
    }

Finally, running this application will produce the following results:

HelloWorld
Testing
Testing
Testing
Testing
Testing

Try to modify the above method with the following method:

    public void run() {
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException ex) {

            }
            // Ensure we have the event lock
            synchronized(UiApplication.getEventLock()) {
                mainScreen.appendLabelText("Testing Again");
            }
        }
    }

Blackberry Development 2: Steps for an app

A step guide for a simple app development by using Eclipse and Blackberry Plug-In. This is the follow up of my previous post Blackberry Development 1: setup environment.

2.1. create a project in Eclipse

To create a new BlackBerry project, click the File menu, and choose New Image from book BlackBerry Project. Name your project HelloWorld, and click Finish.

What is created?

The IDE will create the following:

  • src folder: Where all our source files will reside
  • res folder: Where all resource files (i.e., images) will reside
  • JRE System Library: The BlackBerry runtime library containing the BlackBerry API (by default, it is OS 7)
  • BlackBerry_App_Descriptor.xml file: A file where you can configure your application, including the name of the application and the icon your application will use

 2.2. Create a main application class

Right-click the HelloWorld project icon in the Package Explorer, and from the pop-up menu, select New Image from bookClass. In the dialog, type the following values:

  • Package: com.henry416
  • Name: HelloWorldTest (you can leave off the .java file extension)
  • Superclass: net.rim.device.api.ui.UiApplication
  •  
 What is created?

The application class is created and performs the following:

  • Create an instance of the application

  • Create the main screen and push it onto the display stack

  • Start the event dispatch thread

package com.henry416;

import net.rim.device.api.ui.UiApplication;

public class HelloWorldTest extends UiApplication {

    public HelloWorldTest() {
        // TODO Auto-generated constructor stub
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

    }

}

2.3. Create a main screen class

Click New Image from book Class again (or right-click the package in the tree view and select New Image from bookClass, and you won’t have to reenter the package name). Fill in the following values:

  • Package: com.henry416

  • Name: HelloWorldMainScreen

  • Superclass: net.rim.device.api.ui.container.MainScreen (or type MainS, and press Ctrl+spacebar)

 What is created?
package com.henry416;

import net.rim.device.api.ui.container.MainScreen;

public class HelloWorldMainScreen extends MainScreen {

}

2.4. Add code to the Hello World Classes

Go back to HelloWorldTest, our main class. Fill in the constructor of HelloWorldApp. This will create the main screen and push it onto the display stack:

class HelloWorldTest extends UiApplication {
    HelloWorldTest() {
        HelloWorldMainScreen mainScreen = new HelloWorldMainScreen();
        pushScreen(mainScreen);
    }
}

The main method will create an instance of our application and start the event dispatcher, which is the mechanism that does all the drawing to the screen, and listens for all user interaction for our application.

class HelloWorldTest extends UiApplication {
   …
    public static void main(String[] args) {
        HelloWorldTest app = new HelloWorldApp();
        app.enterEventDispatcher();
    }
}

The enterEventDispatcher method will never return as long as the application is running. Essentially, the thread that entered the main application becomes the event dispatch thread. We’ll explore this in greater depth later, but for now, just remember that the method won’t return during the application’s normal life cycle.

2.5. Code the Main Screen Classes

Add some GUI components to our main screen class with the following code for HelloWorldMainScreen.java:

public class HelloWorldMainScreen extends MainScreen {
    public HelloWorldMainScreen() {
        net.rim.device.api.ui.component.LabelField labelField = new
net.rim.device.api.ui.component.LabelField("Hello World");

        add(labelField);
    }
}

Note that we subclass MainScreen instead of Screen because MainScreen gives us a couple of things automatically—namely a basic layout manager (to position our UI controls on the screen) and a default menu.  

2.6. Test the app in the simulator

Click the arrow next to the debug icon on the Eclipse toolbar, and select Debug Configurations. Each configuration can have different debug parameters, and as you develop applications, you’ll likely end up with a few different configurations for debugging different OS versions, screen sizes, and so on.

Select the BlackBerry Simulator icon on the left side, and click the New button on the toolbar in the dialog window.

On the Project tab, check the newly created HelloWorld project. Then click the Debug button at the bottom of the dialog. The simulator will launch with your application deployed.

After you click the Debug button, the simulator will start up. When it is finished, you will see your HelloWorldTest on the BlackBerry simulator home screen,

Click the app icon to test…