I have been playing around with blackberry development for a while now. During this time I have noticed a common pattern of how a gui project should look. This is my attempt on creating a shell for all gui projects, called skeleton. Just keep in mind that this will change over time as this was done in about an hour, so it does not contain every component that would constitute a complete shell yet. But it is a start.
Before I start I am developing on windows using the eclipse development environment for eclipse.
Firstly, I created a standard project using the eclipse ide with 3classes and a few added folders (models, img and icon all in the root folder):
1. MainEntry.java
package me.bayes.skeleton;
import me.bayes.skeleton.gui.FrontScreen;
import me.bayes.skeleton.gui.SplashScreen;
import net.rim.device.api.ui.UiApplication;
/**
* This is the mail entry point of the application.
*
* @author Kevin Bayes
*
*/
public final class MainEntry extends UiApplication {
public MainEntry() {
FrontScreen frontScreen = new FrontScreen();
new SplashScreen(this, frontScreen);
}
public static void main(String[] args) {
MainEntry entry = new MainEntry();
entry.enterEventDispatcher();
}
}
2. FrontScreen.java – The front screen will be the landing page once you have exited the splash screen. As part of this and I have added a sample of using preprocessing to cater for multiple devices.
//#preprocess
package me.bayes.skeleton.gui;
import net.rim.device.api.ui.component.TextField;
import net.rim.device.api.ui.container.MainScreen;
/**
* Currently this is empty, but it does show the usefulness of preprocess
* @author Kevin Bayes
*
*/
public final class FrontScreen extends MainScreen {
public FrontScreen() {
super();
TextField text = new TextField();
//#ifdef RIM_6.0.0
text.setText("It's 6.0.0");
//#else
text.setText("Not 6.0.0");
//#endif
add(text);
}
}
3. SplashScreen.java – The splash screen is the introduction to your application and can be used to mask the booting up of your application. Here preprocessing has not been used as the image that will be loaded will be decided at compile time using an ant build.
package me.bayes.skeleton.gui;
import java.util.Timer;
import java.util.TimerTask;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.BitmapField;
import net.rim.device.api.ui.container.MainScreen;
/**
* @author Kevin Bayes
*
*/
final public class SplashScreen extends MainScreen {
private MainScreen next;
private Timer timer = new Timer();
private UiApplication application;
//This splash screen is an image read from the root folder of the application
private static final Bitmap _bitmap = Bitmap.getBitmapResource("skeleton.png");
public SplashScreen(UiApplication ui, MainScreen next) {
super (Field.USE_ALL_HEIGHT|Field.FIELD_LEFT);
this.application = ui;
this.next = next;
this.add(new BitmapField(_bitmap));
/*
* create a listener to allow the user to exit the splash screen
* manually or override the navigation events as done below.
*
* the splash screen listener should implement net.rim.device.api.system.KeyListener.
**/
//SplashScreenListener listener = new SplashScreenListener(this);
//this.addKeyListener(listener);
//create a timer to count down to the splash screens exit
timer.schedule(new ExitSplashCountDown(), 5000L);
application.pushScreen (this);
}
/**
*
When the splash screen exits three things happen
*
*
- The timer is canceled.
*
- You pop the splash screen off the stack.
*
- You push the main screen onto the stack.
*
*/
public void dismiss() {
timer.cancel();
application.popScreen (this);
application.pushScreen (next);
}
/**
* *
This {@link TimerTask} is used to make sure the splash screen exits and
* * does not display forever.
* *
* * @author Kevin Bayes
* *
*/
private final class ExitSplashCountDown extends TimerTask
{
public void run() {
ExitSplashThread dThread = new ExitSplashThread();
application.invokeLater (dThread);
}
}
/**
* *
Used by the {@link ExitSplashCountDown} to exit the splash screen.
* *
* * @author Kevin Bayes
* *
*/
private final class ExitSplashThread implements Runnable {
public void run() {
dismiss();
}
/*
* * When you click the navigation then the screen should exit and go to your applications main screen
* *
* * (non-Javadoc)
* * @see net.rim.device.api.ui.Screen#navigationClick(int, int)
* */
protected boolean navigationClick(int status, int time) {
dismiss();
return true;
}
/*
* * Make sure nothing happens when the navigation senses movement
* *
* * (non-Javadoc)
* * @see net.rim.device.api.ui.Screen#navigationMovement(int, int, int, int)
*/
protected boolean navigationMovement(int dx, int dy, int status, int time) {
return false;
}
/*
* * Make sure nothing happens when unclick occurs
* *
* * (non-Javadoc)
* @see net.rim.device.api.ui.Screen#navigationUnclick(int, int)
*/
protected boolean navigationUnclick(int status, int time) {
return false;
}
}
}
If you would like for the sake of development you should fill in the BlackBerry_App_Descriptor.xml and a preprocessing tag of RIM_6.0.0 to test the preprocessing during development. Now once you have completed your development and want to build the application for multiple platforms. To do this I have used the bb-ant-tool. Mu script only includes preprocessing tags and compiling, I will add features like the signing tool at a later stage. Now to buid the skeleton project I created the following ant script:
<project name="Skeleton Project" basedir="." default="build">
<!-- Default phone is torch -->
<property file="${basedir}/models/9800.properties" />
<!-- Give your project title and version (Same as blackberry app descriptor) -->
<property name="project.title" value="Skeleton"/>
<property name="project.version" value="1.0.0"/>
<property name="blackberry.ant.library.location" value="D:/Programming/bb-ant-tools-1.2.11-bin"></property>
<!-- cdlc means Rimlet -->
<property name="application.type" value="cldc"></property>
<!-- set the jde home -->
<property name="jde.home" value="D:/Programming/ide/eclipse-blackberry/plugins/net.rim.ejde.componentpack6.0.0_6.0.0.29/components" />
<!-- set the build directory -->
<property name="build.directory" value="${basedir}/build"></property>
<!-- create an ant task for blackberry -->
<taskdef resource="bb-ant-defs.xml" classpath="${blackberry.ant.library.location}/bb-ant-tools.jar"/>
<target name="clean">
<description>
Delete all the previous built projects.
</description>
<delete dir="${build.directory}" failonerror="no"></delete>
<delete file="${jde.home}/simulator/${project.title}_${model}.cod" failonerror="no"/>
</target>
<target name="clean-simulator">
<description>
1. Run the simulators clean file.
2. Delete the application from the simulator
</description>
<exec executable="${jde.home}\simulator\clean.bat" dir="${jde.home}\simulator"/>
<exec executable="${jde.home}\simulator\fledge.exe" dir="${basedir}\simulator-data">
<arg value="/app=${jde.home}\simulator\Jvm.dll"/>
<arg value="/handheld=${model}"/>
<arg value="/clear-flash"/>
<arg value="/shutdown-after-startup"/>
</exec>
</target>
<target name="setup">
<description>
Create a build directory to hold exactly the source
and resource files for the selected device model.
Then copy all the necesary files.
</description>
<mkdir dir="${build.directory}\img"/>
<mkdir dir="${build.directory}\res"/>
<mkdir dir="${build.directory}\src"/>
<mkdir dir="${build.directory}\${project.title}"/>
<copy todir="${build.directory}\src">
<fileset dir="${basedir}\src"/>
</copy>
<copy file="${basedir}\icon\${size.icon}\${project.title}_icon.png"
tofile="${build.directory}\img\${project.title}_icon.png"
/>
<copy todir="${build.directory}\img">
<fileset dir="${basedir}\img\${size.screen}"/>
</copy>
<copy todir="${build.directory}\res">
<fileset dir="${basedir}\res"/>
</copy>
</target>
<target name="build" depends="setup">
<description>
We are going to compile the project and use the tags for preprocessing.
</description>
<rapc destdir="${build.directory}\${project.title}" output="${project.title}"
srcdir="${build.directory}">
<jdp type="${application.type}" title="${project.title}"
icon="../img/${project.title}_icon.png" />
<define tag="RIM_${rim.version}"/>
<define tag="SCREEN_${size.screen}"/>
</rapc>
</target>
<target name="deliver" depends="clean, build">
<copy file="${build.directory}\${project.title}\${project.title}.cod"
tofile="${jde.home}\simulator\${project.title}_${model}.cod"
/>
<copy file="${build.directory}\${project.title}\${project.title}.cod"
tofile="${basedir}\delivery\${project.title}_${model}.cod"
/>
<delete dir="${build.directory}"/>
</target>
</project>
Now all you need to do is to create multiple property files in the models directory and there you go build away anywhere…. I will complete a more detailed description as I go along but for now I believe this will suffice.
Please comment about anything you would like me to include in the skeleton project.
Skeleton Project Download