Tuesday, November 20, 2012
Using NULL constants
First thing - I do not use an interface nor a Null class. Second thing - I use a constant to hold the Null object.
class MyClass {
public static final MyClass NULL = new MyClass();
}
If I add a method to MyClass that changes the object state I change the NULL initialization to use an inner class.
class MyClass {
public static final MyClass NULL = new MyClass() {
public void setAttribute(int newValue) {}
};
private int attribute;
public void setAttribute(int newValue) {
this.attribute = newValue;
}
}
Tuesday, July 17, 2012
One million downloads
First version went live on July 16, 2007. With it I learned how to create a graphical interface that can adapt to the screen size and wrote my findings at this blog.
Up until now I did now earn a dime with this app, but the pride is big nonetheless!
If you've got a phone that runs Java, install and see what other MILLION people has seen. ;)
http://www.getjar.com/mobile/11226/Chess
Tuesday, June 26, 2012
Single Canvas Theory
I advocate to use a single [Game]Canvas child because we do not how how much memory each [Game]Canvas instance might need. Different JVMs will use more or less memory for [Game]Canvas and Displayable classes.
But it is a bad idea to keep all UI logic in a sigle file. We could easily get above a thousand lines of code.
A simple way to use a single Canvas child and split UI logic in different classes is to use a Paintable class. It will have all event delivery methods from Canvas ([show|hide]Notify, key[Press|Repeat|Releas]ed, pointer[Press|Dragg|Releas]ed and paint) so it can render itself and react to visibility transiction and user input. If we were to use a single GameCanvas instance the approach would be different.
The differences to Canvas are:
- key[Press|Repeat|Releas]ed methods will receive an extra parameter: action, which is initiated with getGameAction(keyCode).
- key[Press|Repeat|Releas]ed and pointer[Press|Dragg|Releas]ed methods will return boolean: true if the screen needs to be repainted.
- from all other Canvas methods only get[Width|Height] are really necessary
Bellow is the code for the Paintable class:
abstract class Paintable { private int width, height; private CommandListener listener; final void init(CommandListener listener, int w, int h) { this.listener = listener; this.width = w; this.height = h; } final public int getWidth() { return width; } final public int getHeight() { return height; } final void repaint() { listener.commandAction(MainCanvas.CMD_REPAINT, null); } final void exit() { listener.commandAction(MainCanvas.CMD_EXIT, null); } /** * @param id one of SCR constants from MainCanvas */ final void show(int id) { Command change = new Command("", Command.SCREEN, id); listener.commandAction(change, null); } boolean keyPressed(int keyCode, int gameAction) { return false; } boolean pointerPressed(int x, int y) { return false; } void showNotify() { } void hideNotify() { } abstract void paint (Graphics g); }Below is my MainCanvas class:
public class MainCanvas extends Canvas implements CommandListener { static final Command CMD_REPAINT = new Command("", Command.SCREEN, 1); static final Command CMD_EXIT = new Command("", Command.EXIT, 1); static final int SCR_SPLASH = 1; static final int SCR_MENU = 2; static final int SCR_PLAY = 3; private Paintable paintable; private int paintableId; private MIDlet midlet; public MainCanvas(MIDlet midlet) { this.midlet = midlet; } public int getGameAction(int keyCode) { int action = 0; try { action = super.getGameAction(keyCode); } catch (Exception e) {} return action; } protected void keyPressed(int keyCode) { if (paintable.keyPressed(keyCode, getGameAction(keyCode))) repaint(); } protected void pointerPressed(int x, int y) { if (paintable.pointerPressed(x, y)) repaint(); } protected void paint(Graphics g) { paintable.paint(g); } public void commandAction(Command c, Displayable d) { if (c == CMD_REPAINT) { repaint(); } else if (c == CMD_EXIT) { midlet.notifyDestroyed(); } else if (c.getCommandType() == Command.SCREEN) { changeScreen(c.getPriority()); } } public void changeScreen(int id) { if (paintableId == id) { return; } Paintable nextPaintable = newPaintableFromId(id); if (nextPaintable != null) { if (paintable != null) { paintable.hideNotify(); } nextPaintable.init(this, getWidth(), getHeight()); paintable = nextPaintable; paintable.showNotify(); paintableId = id; repaint(); } } private Paintable newPaintableFromId(int id) { Paintable nextPaintable = null; switch (id) { case SCR_SPLASH: nextPaintable = new SplashScreen(); break; case SCR_MENU: nextPaintable = new MainMenuScreen(); break; case SCR_PLAY: nextPaintable = new BoardScreen(); break; } return nextPaintable; } }Below is the MIDlet that initiates and show MainCanvas:
public class C extends MIDlet { private MainCanvas mainCanvas; public C() { mainCanvas = new MainCanvas(this); mainCanvas.changeScreen(MainCanvas.SCR_SPLASH); } protected void startApp() { Display.getDisplay(this).setCurrent(mainCanvas); } protected void pauseApp() { } protected void destroyApp(boolean arg0) { } }When SplashScreen needs to show MainMenuScreen it will call show(MainCanvas.SCR_MENU).
Related topics: