dcsimg
J2ME App Code-Review requested!
0 posts in topic
Thread View Thread View
TOPIC ACTIONS:
 

J2ME App Code-Review requested!...
jodter
Fri Jan 31, 2014 12:30 PM

Hi there,

i hail from the world of PHP programming but have lately been working on an app for my old-as-hell nokia x3-00 with J2ME. The App is about learning and remembering basic japanese symbols, such as hiragana, katakana and radicals.

Since i'm pretty new to this (i did some Java back in school though) i would like to ask for some constructive criticism on the following code example mainly regarding performance issues.

One small note ahead. My lame-ass handy does not support UTF-8, so i was forced to use sprites.

Main File:

 
					package nihongotrainer;
				
 


import java.io.IOException;
import java.util.Hashtable;
import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.AlertType;
import javax.microedition.lcdui.Choice;
import javax.microedition.lcdui.ChoiceGroup;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.Item;
import javax.microedition.lcdui.ItemStateListener;
import javax.microedition.lcdui.List;
import javax.microedition.midlet.MIDlet;

/**
 * @author JodMinster
 */
public class Midlet extends MIDlet implements CommandListener, ItemStateListener {

    private Display Screen;

    private StartScreen Start;

    private Trainer Train;

    private Form Options;

    private List Menu;

    private int language = 0;

    private boolean[] LangFlags = {true, false};

    private boolean[] ModeFlags = {true, true, true};

    private boolean[] OrderFlags = {true, false};
   
    private boolean[] DisplayFlags = {true, false, false};

    private final Hashtable I18n = new Hashtable(2);

    private Command GO, BACK, START;

    private int bonusCount = 0;

    private void setupLanguages() {
        Hashtable en = new Hashtable();
        Hashtable de = new Hashtable();

        en.put("screen", "Press start");
        en.put("start", "start");
        en.put("go", "go");
        en.put("back", "back");
        en.put("list_start", "New Game");
        en.put("list_continue", "Continue");
        en.put("list_options", "Options");
        en.put("list_impress", "Impressum");
        en.put("list_exit", "Exit");
        en.put("language", "Language");
        en.put("en", "English");
        en.put("de", "German");
        en.put("mode", "Mode");
        en.put("hira", "Hiragana");
        en.put("kata", "Katakana");
        en.put("rad", "Radicals");
        en.put("order", "Sequence");
        en.put("alpha", "Ordered");
        en.put("random", "Random");
        en.put("form", "Options");
        en.put("menu", "Japanese Trainer");
        en.put("running", "Continue Game");
        en.put("run_msg", "No running game found to continue.");
        en.put("no_modes", "Error");
        en.put("no_mode_msg", "No modes selected.");
        en.put("display", "Display");
        en.put("sym_txt", "Symbol → Text");
        en.put("txt_sym", "Text → Symbol");
        en.put("ts_rand", "Symbol ↔ Text");

        de.put("screen", "Start drücken");
        de.put("start", "beginnen");
        de.put("go", "los");
        de.put("back", "zurück");
        de.put("list_start", "Neues Spiel");
        de.put("list_continue", "Fortsetzen");
        de.put("list_options", "Optionen");
        de.put("list_impress", "Impressum");
        de.put("list_exit", "Beenden");
        de.put("language", "Sprache");
        de.put("en", "Englisch");
        de.put("de", "Deutsch");
        de.put("mode", "Modus");
        de.put("hira", "Hiragana");
        de.put("kata", "Katakana");
        de.put("rad", "Radikale");
        de.put("order", "Reigenfolge");
        de.put("alpha", "Geordnet");
        de.put("random", "Zufällig");
        de.put("form", "Optionen");
        de.put("menu", "Japanisch Trainer");
        de.put("running", "Spiel Fortsetzen");
        de.put("run_msg", "Kein laufendes Spiel zum Fortsetzen gefunden.");
        de.put("no_modes", "Fehler");
        de.put("no_mode_msg", "Keine Modi ausgewählt.");
        de.put("display", "Anzeige");
        de.put("sym_txt", "Symbol → Text");
        de.put("txt_sym", "Text → Symbol");
        de.put("ts_rand", "Symbol ↔ Text");

        I18n.put("en", en);
        I18n.put("de", de);
    }

    public String getI18nLbl(String lbl) {
        String key = language == 0 ? "en" : "de";

        return (String) ((Hashtable) I18n.get(key)).get(lbl);
    }

    public void toggleMenu() {
        setActive(Menu);
    }

    private void init() {
        if (Screen == null) {
            Screen = Display.getDisplay(this);
        }

        GO = new Command(getI18nLbl("go"), Command.SCREEN, 1);
        START = new Command(getI18nLbl("start"), Command.HELP, 1);
        BACK = new Command(getI18nLbl("back"), Command.EXIT, 1);

        if (Start == null) {
            Start = new StartScreen(this, getI18nLbl("screen"));
        } else {
            Start.setText(getI18nLbl("screen"));
        }

        Menu = _buildList();
    }
   
    private void setActive(Displayable Element) {
        Screen.setCurrent(Element);
    }

    public Midlet() {
        setupLanguages();
        init();
    }

    public void startApp() {
        setActive(Start);
    }

    public void pauseApp() {
        // do nothing
    }

    public void destroyApp(boolean unconditional) {
        notifyDestroyed();
    }

    public void commandAction(Command c, Displayable d) {
        String pre = "nihongotrainer.";
        String lbl = c.getLabel();
        String cls = d.getClass().getName();

        //System.err.println(cls + " " + lbl);
        if (((cls.equals(pre + "StartScreen") || cls.equals(pre + "Bonus")) && lbl.equals(getI18nLbl("start")))
                || (cls.equals(pre + "OptionsForm"))
                || (cls.equals(pre + "List") && lbl.equals(getI18nLbl("start")))) {
            setActive(Menu);
        }

        if (cls.equals(pre + "Menu") && lbl.equals(getI18nLbl("go"))) {
            switch (((Menu) d).getSelectedIndex()) {
                case 0:
                    ChoiceGroup modes = (ChoiceGroup) _getOptions().get(1);
                    boolean[] actOpt = new boolean[modes.size()];
                    modes.getSelectedFlags(actOpt);

                    boolean actOpts = false;
                    for (int x = 0; x < actOpt.length; x++) {
                        if (actOpt[x] == true) {
                            actOpts = true;
                            break;
                        }
                    }

                    if (actOpts == false) {
                        setActive(new Alert(getI18nLbl("no_modes"), getI18nLbl("no_mode_msg"), null, AlertType.ERROR));
                        return;
                    }

                    if (Train != null) {
                        // TODO: confirm restart on running game
                    }

                    Train = new Trainer(this, _getOptions());

                    setActive(Train);

                    break;
                case 1:
                    // TODO: don"t show continue if train == null
                    if (Train != null) {
                        setActive(Train);
                    } else {
                        setActive(new Alert(getI18nLbl("running"), getI18nLbl("run_msg"), null, AlertType.ERROR));
                    }
                    break;
                case 2:
                    setActive(_getOptions());
                    break;
                case 3:
                    setActive(Start);
                    break;
                case 4:
                    destroyApp(true);
                    break;
                }
        }
    }
   
    private Form _getOptions()
    {
        if (Options == null) {
            Options = _buildForm();
        }
       
        return Options;
    }

    private Form _buildForm() {
        Form form = new OptionsForm(getI18nLbl("form"));

        form.append(_buildLangSelection());
        form.append(_buildModeSelection());
        form.append(_buildOrderSelection());
        form.append(_buildDisplaySelection());
        form.addCommand(BACK);
        form.setCommandListener(this);
        form.setItemStateListener(this);

        return form;
    }

    private List _buildList() {
        List list = new Menu(getI18nLbl("menu"));

        list.append(getI18nLbl("list_start"), null);
        list.append(getI18nLbl("list_continue"), null);
        list.append(getI18nLbl("list_options"), null);
        list.append(getI18nLbl("list_impress"), null);
        list.append(getI18nLbl("list_exit"), null);
        list.addCommand(GO);
        list.setCommandListener(this);

        return list;
    }

    private ChoiceGroup _buildLangSelection() {
        ChoiceGroup LangList = new ChoiceGroup(getI18nLbl("language"), Choice.EXCLUSIVE);

        try {
            LangList.append(getI18nLbl("en"), Image.createImage("/en.png"));
            LangList.append(getI18nLbl("de"), Image.createImage("/de.png"));
        } catch (IOException ex) {
        }
        LangList.setSelectedFlags(LangFlags);

        return LangList;
    }
   
    private ChoiceGroup _buildDisplaySelection()
    {
        ChoiceGroup DisplayList = new ChoiceGroup(getI18nLbl("display"), Choice.EXCLUSIVE);
        DisplayList.append(getI18nLbl("sym_txt"), null);
        DisplayList.append(getI18nLbl("txt_sym"), null);
        DisplayList.append(getI18nLbl("ts_rand"), null);
       
        DisplayList.setSelectedFlags(DisplayFlags);

        return DisplayList;   
    }

    private ChoiceGroup _buildModeSelection() {
        ChoiceGroup ModeList = new ChoiceGroup(getI18nLbl("mode"), Choice.MULTIPLE);
        try {
            ModeList.append(getI18nLbl("hira"), Image.createImage("/hira.png"));
            ModeList.append(getI18nLbl("kata"), Image.createImage("/kata.png"));
            ModeList.append(getI18nLbl("rad"), Image.createImage("/bushu.png"));
        } catch (IOException ex) {
        }
        ModeList.setSelectedFlags(ModeFlags);

        return ModeList;
    }

    private ChoiceGroup _buildOrderSelection() {
        ChoiceGroup OrderList = new ChoiceGroup(getI18nLbl("order"), Choice.EXCLUSIVE);
        try {
            OrderList.append(getI18nLbl("alpha"), Image.createImage("/order.png"));
            OrderList.append(getI18nLbl("random"), Image.createImage("/random.png"));
        } catch (IOException ex) {
        }
        OrderList.setSelectedFlags(OrderFlags);

        return OrderList;
    }

    public void itemStateChanged(Item item) {
        ChoiceGroup cg = (ChoiceGroup) item;

        if (item.getLabel().equals(getI18nLbl("language"))) {
            cg.getSelectedFlags(LangFlags);
            language = cg.getSelectedIndex();
            init();
            Options = null;
            setActive(_getOptions());
        }

        if (item.getLabel().equals(getI18nLbl("mode"))) {
            cg.getSelectedFlags(ModeFlags);
        }

        if (item.getLabel().equals(getI18nLbl("order"))) {
            cg.getSelectedFlags(OrderFlags);
        }

        if (item.getLabel().equals(getI18nLbl("display"))) {
            cg.getSelectedFlags(DisplayFlags);
        }
    }
}

class Menu extends List {

    public Menu(String title) {
        super(title, List.IMPLICIT);
    }
}

class OptionsForm extends Form {

    public OptionsForm(String title) {
        super(title);
    }
}

Trainer File:


import java.io.IOException;
import java.util.Hashtable;
import java.util.Random;
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.ChoiceGroup;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.Sprite;

/**
 * @author JodMinster
 */
public class Trainer extends Canvas {

    private final Midlet Parent;
   
    /**
     * current position in active
     */
    private int pointer = 0;
   
    private int[] hira; // = new int[48]; // 0 .. 47
    /*
    private int[] hira_mu; // = new int[25]; // 48 .. 72
    private int[] hira_vo; // = new int[21]; // 73 .. 93
    private int[] hira_mu_vo; // = new int[15];// 94 .. 108
    */
   
    private int[] kata; // = new int[48]; // 109 .. 156
    /*
    private int[] kata_mu; // = new int[25]; // 157 ,, 181
    private int[] kata_vo; // = new int[21]; // 182 .. 202
    private int[] kata_mu_vo; // = new int[15]; // 203 .. 217
    */
   
    private int[] radicals; // = new int[214]; // 218 .. 431 (218 - 293, 294 - 368, 369 - 432)
   
    private String[] kana; // = new String[48];
   
    private String current;
   
    /**
     * values from hira and kata arrays which are used in this session
     * array gets extended later
     */
    private int[] active = new int[0];
   
    private Image hiraTpl, kataTpl, radTpl;
   
    private String templateName = "";
   
    private Image template;
   
    private boolean textDrawn = true;
   
    private boolean additionalText = false;
   
    private String mode;
   
    // 0 , s -> t, 1 t -> s, 2 rand
    private int whatToShow = 0;
   
    private boolean keepShowMode = false;
   
    private boolean showMode = true;
   
    /**
     * init fucking java arrays...
     */
    private void _init(boolean loadHira, boolean loadKata, boolean loadRad)
    {
        if (loadHira) hira = new int[48];
        if (loadKata) kata = new int[48];
        if (loadRad) radicals = new int[214];
       
        if (loadHira || loadKata) {
            kana = new String[48];
           
            String[] g = {"", "k", "s", "t", "n", "h", "m", "y", "r", "w"};
            String[] h = {"a", "i", "u", "e", "o"};
            String sym;
            int i = 0;
            for (int a = 0; a < g.length; a++) {
                for (int b = 0; b < h.length; b++) {
                    sym = g[a] + h[b];
                    if (sym.equals("si")) { sym = "shi"; }
                    if (sym.equals("ti")) { sym = "chi"; }
                    if (sym.equals("tu")) { sym = "tsu"; }
                    if (sym.equals("hu")) { sym = "fu"; }
                    if (sym.equals("yi") || sym.equals("ye")) { continue; }
                    if (sym.equals("wu")) { sym = "n"; }

                    kana[i++] = sym;
                }
            }
       
            for (int x = 0; x < 48; x++) {
                if (loadHira) hira[x] = x;
                if (loadKata) kata[x] = x + 109;
            }
        }
       
        /*
        for (int x = 0; x < 25; x++) {
            hira_mu[x] = x + 48;
            kata_mu[x] = x + 157;
        }
               
        for (int x = 0; x < 21; x++) {
            hira_vo[x] = x + 73;
            kata_vo[x] = x + 182;
        }
       
        for (int x = 0; x < 15; x++) {
            hira_mu_vo[x] = x + 94;
            kata_mu_vo[x] = x + 203;
        }
        */
       
        if (loadRad) {
            for (int x = 0; x < 214; x++) {
                radicals[x] = x + 218;
            }
        }
    }
   
    /**
     * constructor
     */
    public Trainer(Midlet papa, Form options)
    {
        setFullScreenMode(true);
       
        Parent = papa;
        // todo analyse options
       
        ChoiceGroup mode = (ChoiceGroup) options.get(1);
        ChoiceGroup order =(ChoiceGroup) options.get(2);
        ChoiceGroup display =(ChoiceGroup) options.get(3);
       
        boolean[] x = new boolean[3];
        mode.getSelectedFlags(x);
       
        _init(x[0], x[1], x[2]);
       
        if (x[0] == true) {
            _add(hira);
        }
       
        if (x[1] == true) {
            _add(kata);
        }
       
        if (x[2] == true) {
            _add(radicals);
        }
       
        whatToShow = display.getSelectedIndex();
       
        if (whatToShow == 1) {
            showMode = false;
        }
       
        if (order.getSelectedIndex() == 1) {
            _shuffleData();
        }
    }
   
    private void _paintImage(Graphics g)
    {
        // get image
        Image symb = _getImage(false);
       
        int x, y;
        x = getWidth()/ 2 - symb.getWidth() / 2;
        y = getHeight() / 2 - symb.getHeight() / 2;
       
        g.drawImage(symb, x, y, 0);
    }

    /**
     * paint
     */
    public void paint(Graphics g)
    {
        // return if nothing selected in options
        if (active.length == 0) {
            Parent.toggleMenu();
            return;
        }
       
        Font f = g.getFont();
       
        _getImage(true);
       
        // background
        g.setColor(0xffffff);
        g.fillRect(0, 0, getWidth(), getHeight());
        g.setColor(0x000000);
       
        // top right: current / count
        String counter = (pointer + 1) + " / " + active.length;
        int strlen = f.substringWidth(counter, 0, counter.length());
        g.drawString(counter, getWidth() - strlen - 15, 15, 0);
        g.drawString(mode, 15, 15, 0);
       
        if (keepShowMode == false && whatToShow == 2) {
            showMode = whatToShow == 0 ? true : (whatToShow == 1 ? false : _getRandom());
        }
       
        if (showMode) {
            _paintImage(g);
            if (textDrawn == false) {
                _drawText(g, f);
            }
        } else {
            _drawText(g, f);
            if (textDrawn == false) {
                _paintImage(g);
            }
        }
       
        if (whatToShow == 2) {
            keepShowMode = !keepShowMode;
        }
       
        textDrawn = !textDrawn;
    }
   
    private boolean _getRandom()
    {
        Random rand = new Random();
        return rand.nextInt(2) == 0;
    }
   
    private void _drawText(Graphics g, Font f)
    {
        String lbl = current.length() > 0 ? current : "???";
        int strlen = f.substringWidth(lbl, 0, lbl.length());
        g.drawString(lbl, getWidth() / 2 - strlen / 2, getHeight() / 2 + 99 / 2 + 20, 0);

        if (additionalText == true) {
            lbl = "???";
            strlen = f.substringWidth(lbl, 0, lbl.length());
            g.drawString(lbl, getWidth() / 2 - strlen / 2, getHeight() / 2 + 137 / 2 + 40, 0);
        }
    }

    /**
     * Called when a key is pressed.
     * @param keyCode
     */
    protected void keyPressed(int keyCode)
    {
        if (keyCode == -5 && pointer < (active.length - 1)) {
            if (textDrawn == true) {
                pointer++;
            }
            repaint();
        } else {
            textDrawn = !textDrawn;
            Parent.toggleMenu();
        }
    }
   
    /**
     * ugly shuffles data
     */
    private void _shuffleData()
    {
        Random rand = new Random();
       
        for (int x = 0; x < active.length; x++) {
            int tmp = active[x];
            int move = rand.nextInt(active.length);
           
            active[x] = active[move];
            active[move] = tmp;
        }
    }

    private void _add(int[] arr) {
        int[] tmp = new int[active.length + arr.length];
       
        for (int x = 0; x < active.length; x++) {
            tmp[x] = active[x];
        }
       
        for (int x = 0; x < arr.length; x++) {
            tmp[x + active.length] = arr[x];
        }
       
        active = tmp;
    }

    private Image _getImage(boolean textOnly)
    {
        Image crop = Image.createImage(textOnly ? 1 : 80,  textOnly ? 1 : 80);
        int imgId = active[pointer];
        additionalText = false;
        current = "";
           
        if (imgId > 217) { // radicals
            mode = "R";
            int section = imgId > 367 ? 2 : (imgId > 292 ? 1 : 0);
            if (textOnly == false) crop = _cropImage(_getTemplate("radicals_" + section), imgId - 218 - (section * 75), 14, 80, 80);
            additionalText = true;
        } else if (imgId > 202) { // muddied + voiced kata
            mode = "K";
            // TODO
        } else if (imgId > 181) { // voiced kata
            mode = "K";
            // TODO
        } else if (imgId > 156) { // muddied kata
            mode = "K";
            // TODO
        } else if (imgId > 108) { // regular katakana
            mode = "K";
            if (textOnly == false) crop = _cropImage(_getTemplate("katakana"), imgId - 109, 5, 80, 80);
            current = kana[imgId - 109];
        } else if (imgId > 93) { // muddied + voiced hira
            mode = "H";
            // TODO
        } else if (imgId > 72) { // vioce hira
            mode = "H";
            // TODO
        } else if (imgId > 47) { // muddied hira
            mode = "H";
            // TODO
        } else {
            mode = "H";
            if (textOnly == false) crop = _cropImage(_getTemplate("hiragana"), imgId, 5, 80, 80);
            current = kana[imgId];
        }
       
        return crop;
    }
   
    private Image _getTemplate(String name)
    {
        if (templateName.equals(name) == false) {
            templateName = name;
            try {
                template = Image.createImage("/" + name + ".png");
            } catch (IOException ex) {
            }
        }
       
        return template;
    }

    private Image _cropImage(Image template, int x, int factor, int w, int h)
    {
        int y = 0;
       
        while (x > factor) {
            x -= factor + 1;
            y++;
        }
       
        return Image.createImage(template, x * w, y * h, w, h, Sprite.TRANS_NONE);
    }
}


Thanks in advance for any answers.

About | Sitemap | Contact