Thursday, May 24, 2007

Responsive UI: do the heavy lifting in backgroup thread

Slow wireless connection, less processing power, less memory, all these factors make JavaME applications tend to feel sluggish. One trick we developers can play is to use background thread to do the heavy lifting parts.

The sample code below shows how one can use a separate thread to perform the time consuming task, while the UI still interacts with user, and update the UI when the task is completed.

Please note that the Runnable object passed to UiApplication.invokeLater() should return quickly. The Runnable object is put into the event queue to be executed by the event dispatcher thread. During the time this runnable is executing, all new UI events are queued so the UI will not respond to any input.


package com.mycompany.sample;

import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.AutoTextEditField;
import net.rim.device.api.ui.component.ObjectChoiceField;
import net.rim.device.api.ui.container.MainScreen;

public final class DemoBackgroundThread extends UiApplication {
public DemoBackgroundThread(){
super();
pushScreen(new EditorScreen());
}

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

private static class EditorScreen extends MainScreen {
private AutoTextEditField _firstNameField;
private AutoTextEditField _lastNameField;
private ObjectChoiceField _timezoneField;
public EditorScreen()
{
super();
_firstNameField = new AutoTextEditField("First Name: ", "");
_lastNameField = new AutoTextEditField("Last Name: ", "");
_timezoneField = new ObjectChoiceField("Timezone: ", new String[]{"Loading Timezones"});
add(_firstNameField);
add(_lastNameField);
add(_timezoneField);
new Thread(new Runnable() {
public void run() {
final String[] zones = new String[6];
zones[0] = "-Select Timezone-";
for(int i = 1; i < zones.length; i++) {
try {
//do the heavy lifting here, like fetching data from remote server or heavy calculations.
Thread.sleep(1000);
} catch (InterruptedException e) {
//who cares
}
zones[i] = "GMT-"+i;
}
UiApplication.getUiApplication().invokeLater(new Runnable(){
public void run() {
_timezoneField.setChoices(zones);
}
});
}
}).start();
}
}
}

Tuesday, May 22, 2007

Debug Blackberry app inside Eclipse

Once you get your eclipse environment setup, it is pretty straight forward to debug your app, thanks to Blackberry JDE, 4.1 and higher comes with JDWP implementation.

Let's first start JDWP, from Start --> All Programs --> Research In Motion --> Blackberry JDE 4.?.? --> JDWP. In this interface, the first main tab "Simulator" configures the simulator to lanch when debugger connects and the other behaviors. Please make sure that in the "General" tab "Launch simulator when debugger connects" is checked. In the second main tab "Communications", you can change the port JDWP listens to. This is the port we will connect to from our eclipse debugger.

With JDWP running, we can go back eclipse. Before we get started, we should increase the debugger's timeout threshold. Start elcipse, go to Window --> Preferences --> Java --> Debug, at the bottom of the dialog, increase the "Debugger timeout" and "Launch timeout" to 10 times longer. :) It is much needed unless you have a monster computer with multiple cores and multiple gigs of memory.

To config the debugger, go to Run --> Debug... In the dialog, select "Remote Java Application" from left hand list, then click on the "New" button; now at the right hand pane, give it a meaningful name, check the remote host and port matches JDWP's, then go to the third tab "Common", check "Debug" option in "Display in Favorites menu" so you don't have to open this dialog next time. Click "Debug" button if you are ready, otherwise click "Close" button to save the configuration.

Now the fun part begins. Edit code, run the ant task to deploy, set break point, click on the debug icon, and repeat this cycle.

Monday, May 21, 2007

Eclipse setup for blackberry development

These are proven-to-work steps to setup your eclipse environment for developing Blackberry applications. I hope this post will make somebody's entry into the RIM development easier.

To get started, do the following if you haven't done so:

  1. Download and install Eclipse
  2. Download and install BlackBerry JDE
  3. Download and install Apache ant
  4. Download RAPC ant task jar file
Now let's setup our eclipse environment.
  1. Start your eclipse, switch to a brand-new workspace, for example: c:\RIM\workspace
  2. go to Window --> Preferences --> Java --> Installed JREs, click on "Add" button.
  3. In the dialog, leave the default "Standard VM" option for JRE type;
  4. Type in a "JRE name" as you like, such as 'RIM JRE';
  5. In "JRE Home Directory", navigate to your installed JDK home, such as 'C:\Program Files\Java\jdk1.6.0';
  6. Leave "Default VM Arguments" blank;
  7. Now select all the jar files in "JRE System Libraries", then click "Remove" button to remove all of them; Click "Add External JARs", navigate to you Blackberry JDE installation folder, select lib/net_rim_api.jar, such as 'C:\Program Files\Research In Motion\BlackBerry JDE 4.2.1\lib\net_rim_api.jar'.
  8. Click "OK" button to add the new JRE.
  9. Check the checkbox of your newly added JRE to make it the default (Optional: select this JRE, click on "Edit" button to see if the system libraries are still like you set. It happened to me a couple times that eclipse added the jars in JRE home back into the list.)
With the eclipse setup, we are ready to create our first project:
  1. Goto File --> New --> Project, select "Java Project", enter Project Name "HelloWorld", Make sure in the JRE group the "RIM JRE" is selected. In the "Project Layout" group, I prefer to have src and class output into separate folders. Click "Finish" button.
  2. Right click the project, select New --> Folder, create a folder named "lib"
  3. Right click the project, select New --> Folder, create a folder named "resources"
  4. Right click "lib" folder, select "import"; in the dialog, select "general" --> "file system", import the anttask-rapc-1.?.jar you downloaded. Right click the jar file and select "Build Path" --> "Add to Build Path".
  5. Follow the same step to import an icon file in GIF format into "resources" folder. (other image formats work too, we use GIF for demo).
  6. Create a package named "com.mycompany.sample"
  7. Create a class named "HelloWorld.java" in this package and paste these code:
    package com.mycompany.sample;

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

    public final class HelloWorld extends UiApplication {

    public HelloWorld(){
    super();
    MainScreen screen = new MainScreen();
    screen.add(new LabelField("Hello world!"));
    pushScreen(screen);
    }
    public static void main(String[] args) {
    new HelloWorld().enterEventDispatcher();
    }
    }
  8. Now right click on the project name and create a new file named "build.xml", copy and paste the following code and edit the JRE and RIM JDK pathes accordingly, also search and replace the simulator batch file "8800.bat" to one that exists in your JDE (this ant build script is modified based on a post in Blackberry Java Forum.)

    <?xml version="1.0" encoding="UTF-8"?>

    <project name="HelloWorld" default="buildRIM" basedir=".">

    <taskdef name="rim" classname="com.etaras.anttask.rapc.RAPC" classpath="lib/anttask-rapc-1.8.jar" />

    <property name="jdehome" value="C:\Program Files\Research In Motion\BlackBerry JDE 4.2.1" />
    <property name="javahome" value="C:\Program Files\Java\jdk1.5.0_11"></property>
    <property name="simulator" value="${jdehome}\simulator" />
    <property name="bin" value="${jdehome}\bin" />

    <target name="debug" depends="buildRIM">
    <copy todir="${simulator}" overwrite="true">
    <fileset dir=".">
    <include name="*.cod" />
    <include name="*.debug" />
    <include name="*.csl" />
    <include name="*.cso" />
    </fileset>
    </copy>
    <exec executable="cmd.exe" dir="${bin}" spawn="true">
    <arg value="/c" />
    <arg value="jdwp.bat" />
    </exec>
    </target>

    <target name="simulate" depends="deploy">
    <exec executable="cmd.exe" dir="${simulator}" spawn="true">
    <arg value="/c" />
    <arg value="8800.bat" />
    </exec>
    </target>

    <target name="deploy" depends="buildRIM">
    <copy todir="${simulator}" overwrite="true">
    <fileset dir=".">
    <include name="*.cod" />
    <include name="*.debug" />
    <include name="*.csl" />
    <include name="*.cso" />
    </fileset>
    </copy>
    </target>

    <target name="buildRIM" description="Composes RIM">
    <rim jdehome="${jdehome}" javahome="${javahome}">
    <workspace src="helloworld.jdw" build="true" update="true">
    <cldc src="helloworld.jdp"
    title="HelloWorld"
    vendor="my company"
    version="0.1"
    description="HelloWorld"
    arguments=""
    systemmodule="false"
    runonstartup="false"
    startuptier="7"
    ribbonposition="0"
    output="helloworld"
    options="-quiet"
    update="true">
    <files dir=".">
    <include name="**/*.java" />
    <include name="resources/**/*.*" />
    </files>
    <icons dir=".">
    <include name="resources/**/*.png" />
    <include name="resources/**/*.gif" />
    </icons>
    </cldc>
    </workspace>
    </rim>
    </target>

    </project>

  9. Open a DOS window, change to the directory where you have your build.xml file, type "ant simulate", this task will build the project, deploy it and start the simulator.
  10. Look for the logo you picked for your HelloWorld app and open it, you should see a blank screen displaying "Hello World!". How exciting!
I will write down my experience of debugging applications inside eclipse in the next couple of days.

Thursday, May 03, 2007

Downgrade default JRE on windows XP

When installing Blackberry signature keys yesterday, I need to downgrade my default JRE on windows XP from 1.6 to 1.5. (Java is so good at maintaining backward compatibility, I seriously want to figure out what made the installation process not working in Java1.6. If you have a clue, please comment. Thanks.)

The complexity of this process caught me off guard. As a linux user, I instinctively went to My Computer --> Properties --> Advanced --> Environment Variables, and set the pathes. It doesn't work this way though. (Gentoo users, enjoy your java-config util and laught at me)

After some digging, here are the steps worked for me.

  1. Copy java.exe, java2.exe, javaws.exe from C:\Program Files\Java\jdk1.5.0_??\bin to C:\WINDOWS\system32\ to overwrite existing 1.6 version files.
  2. Open registry editor, goto Start --> Run, type in "regedit" and enter.
  3. Do a search for "JavaSoft", you should find something under HKEY_LOCAL_MACHINE -->SOFTWARE --> JavaSoft --> Java Runtime Environment, modify "CurrentVersion" key to "1.5" or the version you want.
  4. Update the correspondent environment variables.

Install RIM Blackberry signature keys and sign .cod file

Waited one week after placing the signature key order with RIM, we finally lost our patience and contacted them. And shortly after that, we received our keys. :)

Three ".csi" files were emailed to us. Installation is straight forward unless you have incompatible Java version. Downloading files onto hard drive, double click on one, you should see a dialog popping up saying "cannot find private key pair file, blah blah" and a "Yes" button at the end to create one. Click on the "Yes" button, if nothing happens you probably have JDK1.6 running and need to downgrade to JDK1.5. Otherwise another dialog will pop up and ask for the registration pin (the 10 digit number you entered when ordering the key) and select a password. Follow the steps to get your first key registered with RIM. Then do the same for the other two. You are done.

Signing your .cod file is straight. Double click on the .cod file, the Signature Tool window with a table listing all the signatures that you need and need not to request for your cod file will pop up. The signatures you need to request depends on the APIs you used in your cod file. Select the rows with category "required" and status "not signed", click the "Request" button, the Signature Tool will talk to RIM server to get the signature needed. Voila, you just got your application signed.

Wednesday, April 25, 2007

Blackberry 7290 application OutOfMemory exception

After testing my application on the simulator, I finally loaded it onto a real blackberry device, model 7290. It was very exciting to see the cute little logo shown up on the screen. Rolling the trackwheel and click, I got an "OutOfMemory" exception thrown right at my face!!! What a bummer.

Both from the Blackberry documentation and the Internet posts, I got the impression that mobile devices have VERY limited memory, just enough to hold some objects and some object references (handlers). So it must be my application using too much memory. I guess there can only be one response from any developer: I need to optimize my code.

So I started optimizing my code, reducing all object creations and references that are not absolutely necessary, sometimes even sacrifice design patterns, best practices and code readability. I guess that is the price you have to pay for efficiency. Did it help? NO.

I was just about to start doing object grouping when I ran over a post on Internet saying it is not your application, it is the JDE version you are using. For the particular device model (7290) and OS version, I need to use Blackberry JDE4.0 versions. The mystery and embarassing OutOfMemory problem was solved just like that.

Eclipse BlackBerry JDE ClassNotFound Exception

Environment: Eclipse 3.1.1, BlackBerry JDE 4.2.1

When I first set up my eclipse for BlackBerry development, I got this exception: The type net.rim.device.internal.ui.Cursor cannot be resolved. It is indirectly referenced from required .class files. After searching the the Internet and the blackberry java forum, I figured out that it is caused by the java compliance level setting. To fix it, go to Window - Preferences - Java - Compiler, set the Java Compliance Level to 1.4.

Monday, April 23, 2007

DocumentBuilderFactory code signing issue

After resolving the outofmemory issue, my code still won't run. I got another exception saying: Error starting : Module must be signed with the RIM Runtime Code Signing Key (RRT).

Hmm, I was pretty sure that I am not using any signed API, but out of 3000 lines of code, it is very much possible to miss one or two. JDE 4.2.1 has a feature that can outline all the signed API calls. It helps only if I can get it working.

Before I eyeball the code line by line, I did a google search and found this post. Ahha, it is a bug in JDE. The DocumentBuilderFactory falsely requires code signing (fixed in 4.2 and higher). Now my only way out is to buy a sign key from RIM.

Accessing remote X-window from windows box

This is not pretty, but it's needed sometimes. (Yeah, I know, your company made you use windows)

There is a good deal of information on this wiki page about Cygwin/X. But to me it seems like too much information so I simplified it for my own reference.

Here are three simple steps to access remote X after you get Cygwin with X installed:

  1. open a Cygwin window and start X server: X -multiwindow &
  2. export DISPLAY=127.0.0.1:0.0
  3. ssh -X username@remote.server
  4. run xclock (personally I prefer xeyes) to test
One thing to keep in mind is that the remote server has to enable X11 forwarding. It is configed in sshd config file /etc/ssh/sshd_config. Search for X11Forwarding.

That is it. If you prefer putty which is another nice tool I use occationally. You can do this:
  1. open a Cygwin window and start X server: X -multiwindow &
  2. Open putty, in Connection --> SSH --> X11 tab, check the box "Enable X11 Forwarding".
  3. Login and you are done, now open an X app like xclock or xeyes, you should see it.

Thursday, December 07, 2006

Copy files from windows to linux

Setting up a cron job to transfer files among linux boxes is easy. But when you mix some windows boxes into the picture, things get complicated. That is because most windows boxes don't have ssh daemon setup.

But one thing you can do is to run pscp on windows to fetch files from Linux. You can download pscp here http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html

To get started you make a .bat file like this on your windows box: c:\path\to\pscp.exe –pw password username@host.of.linux:/path/to/file c:\path\to\destination
Then you use windows scheduler to schedule a task to run this batch file.

Of course to make it more secure (or just for the peace of mind) you want to hide your password, you can use a public/private key pair. For details reference this doc: http://www.tartarus.org/~simon/puttydoc/Chapter5.html

Thursday, November 09, 2006

Today when I install a package on my newly installed Ubuntu box, I got this error when run ./configure: C compiler cannot create executables. I installed gcc then but still getting the same error.

By search the Ubuntu forum, I found this command to quickly install a c compiler, maybe other compilers too.

apt-get install build-essential


Just a quick tip for beginners running into the same problem.

Tuesday, October 31, 2006

When doing JasperReports yesterday, I encoutered a weird problem. I have some text fields that holds long strings, so the text has to be wrapped. So I set the text fields to stretch with overflow. It worked fine in iReports 1.2.6. But after deploying it to a web application (Centric CRM), some text fields got the last line cut off, just the last line. And this is not happening on all fields in a page, just some.

I tried different versions of JasperReports and Lowagie iText libraries without any luck. Eventually I figured it out. I have the text fields height set to 18 pixels and my detail band set to 20 pixels so I can get a little padding on top and bottom. Somehow these little padding confused JasperReports. After setting all textfields and band to 20 pixels height, everything worked fine. To archieve the little padding, I set the padding in the Border tab in Properties dialog.

Long story short: When doing JasperReports, if you get the last line cut off when setting Textfield to stretch with overflow, check the text field height and band height. It may help.

Thursday, October 19, 2006

Top is a simple yet powerful command to see what is going on in your Linux system.

The most straight forward way to use top is typing top in your command line. This will give a a quick view of the processes in the system. Those key strokes are useful in this mode:

  1. q, quit
  2. space or enter, refresh the view
  3. M, sort by %MEM column
  4. T, sort by TIME column
  5. P, sort by %CPU column
  6. m, toggle memory usage section display (less useful)
  7. t, toggle task/cpu section display (less useful)
You can also run top in batch mode and pipe results out for post processing. For example:
top -b > /tmp/top.output
This will give you one snapshot. For multiple iterations, you can use -n # option. Also you can limit your output to certain processes by specifying process id. For example:
top -b -n 5 -p 12639, 6932 > /tmp/top.output
This will give you 5 iterations of usage of process 12639 and 6932

One last option in batch mode you may need is -u or -U which is the user id or name. For example:
top -b -n 2 -u alex
or
top -b -n 2 -u 1012

You can set up a cron job to run top periodically and process the output if your application doesn't have more sophisticated monitoring mechanism built in.