java-memidlet

How do you organize your code in a j2me project?


Sorry if what I'm about to ask you is a silly question, but since I'm taking my first steps into j2me I have to do it. I know that you can have multiple screens in a single MIDlet, but that doesn't seem to be a good idea when you're going to have a considerable number of screens(more than 10) as it would end up in a complete mess. So here's the question(not sure if possible), how do you usually organize your code in a j2me project? Or do you put everything inside a single MIDlet or do you separate your code into different MIDlets, one per screen, as we usually do in web or desktop applications??

I also noticed that when a project have multiple MIDlets and you launch the emulator, you have the possibility to start each of them. If you can have different functionality in different MIDlets, being able to run any MIDlet without following a specific order,doesn't seem very convenient since a MIDlet might depend on the data that is read in a previous MIDlet.

Please if it is possible to separate different functionality into different MIDlets , do you think you could give a general idea of how to do it?? Which steps to take in general.

Thanks in advance.


Solution

  • General rule: Don't try to get to complex in a single MIDlet :), something I rather like about java-me, i.e. do one thing well ...

    The MIDlet corresponds to an application, since it is subjected to life cycle management.

    In simple cases (i.e. in most cases) I let it implement the CommandListener interface, too, so in MVC terms it is the controller. The controller logic is implemented in the commandAction method (basically if then else on the combination command and screen).

    The different screens like List and TextBox instances correspond to the views in MVC. Put those in separate *.java files. A screen could be tied to an object from your model (e.g an editor) so pass it to the screen in the MIDlet's commandAction method.

    I have seen examples where the screens implement the commandListener, but to me that's mixing concepts and generally less maintainable ...

    You are fairly free in your choice of implementing the model part, however you might want to look into the javax.microedition.rms package for persistence and there are persistent implementations for contacts and calendar entries ...

    Let's say you have the following domain object class (DomainObject.java):

    package mvc.midlet;
    
    public class DomainObject {
        public String name = "";
        public String street = "";
        public String phone = "";
    }
    

    and you want an app to create up to 10 objects, with an overview screen (a list of object) and an editor for the oject.

    Here is the code for the overview screen (Overview.java):

    package mvc.midlet;
    
    import javax.microedition.lcdui.List;
    
    public class Overview extends List {
    
        public static Overview create(DomainObject[] data) {
            int i = 0;
            for(; i < data.length; i++) {
                if(data[i] == null) break;
            }
            String[] names = new String[i];
            for(int j = 0; j < i; j++) {
                names[j] = data[j].name;
            }
            return new Overview(names);
        }
    
        protected Overview(String names[]) {
            super("Overview", IMPLICIT, names, null);
        }
    
    }
    

    and here is the editor code (Editor.java):

    package mvc.midlet;
    
    import javax.microedition.lcdui.Form;
    import javax.microedition.lcdui.Item;
    import javax.microedition.lcdui.TextField;
    
    public class Editor extends Form {
    
        public static Editor create(DomainObject object, boolean isNew) {
            return new Editor(object, isNew);
        }
    
        private final DomainObject object;
        public final boolean isNew;
        public DomainObject getObject() {
            return object;
        }
    
        private final TextField name;
        private final TextField street;
        private final TextField phone;
    
        protected Editor(DomainObject object, boolean isNew) {
            super("Edit");
            this.object = object;
            this.isNew = isNew;
            this.name = new TextField("Name", object.name, 10, TextField.INITIAL_CAPS_WORD);
            this.append(name);
            this.street = new TextField("Street", object.street, 10, TextField.INITIAL_CAPS_WORD);
            this.append(street);
            this.phone = new TextField("Phone", object.phone, 10, TextField.PHONENUMBER);
            this.append(phone);
        }
    
        public String getName() {
            return name.getString();
        }
        public String getStreet() {
            return street.getString();
        }
        public String getPhone() {
            return phone.getString();
        }
        public void saveValues() {
            object.name = getName();
            object.street = getStreet();
            object.phone = getPhone();
        }
    }
    

    And finally the MIDlet that controls it all (MvcMIDlet.java):

    /**
     * 
     */
    package mvc.midlet;
    
    import javax.microedition.lcdui.Command;
    import javax.microedition.lcdui.CommandListener;
    import javax.microedition.lcdui.Display;
    import javax.microedition.lcdui.Displayable;
    import javax.microedition.midlet.MIDlet;
    import javax.microedition.midlet.MIDletStateChangeException;
    
    /**
     * @author cm
     *
     */
    public class MvcMIDlet extends MIDlet implements CommandListener {
    
        private Command add = new Command("New", Command.SCREEN, 0x01);
        private Command edit= new Command("Edit", Command.SCREEN, 0x01);
        private Command exit= new Command("Exit", Command.EXIT, 0x01);
        private Command ok= new Command("OK", Command.OK, 0x01);
    
        DomainObject[] data = new DomainObject[10];
        DomainObject current = null;
    
        /**
         * Initialize some sample data
         */
        public MvcMIDlet() {
            data[0] = new DomainObject();
            data[0].name = "Hans";
            data[1] = new DomainObject();
            data[1].name = "Franz";
        }
    
        protected void startApp() throws MIDletStateChangeException {
            showOverview();
        }
    
        /***
         * create an overview, add commands and show it
         */
        private void showOverview() {
            Overview overview = Overview.create(data);
            overview.addCommand(edit);
            overview.addCommand(add);
            overview.addCommand(exit);
            overview.setCommandListener(this);
            Display.getDisplay(this).setCurrent(overview);
        }
    
        /***
         * create an editor for the given object, add commands and show it
         */
        private void showEditor(DomainObject object, boolean isNew) {
            Editor editor = Editor.create(object, isNew);
            editor.addCommand(ok);
            editor.addCommand(exit);
            editor.setCommandListener(this);
            Display.getDisplay(this).setCurrent(editor);
        }
    
        public void commandAction(Command c, Displayable d) {
            if(d instanceof Overview) {
                if(c == edit) {
                    int i = ((Overview) d).getSelectedIndex();
                    showEditor(data[i], false);
                }
                else if(c == add) {
                    showEditor(new DomainObject(), true);
                }
                else if(c == exit) {
                    this.notifyDestroyed();
                }
    
            }
            else if(d instanceof Editor) {
                if(c == ok) {
                    ((Editor) d).saveValues();
                    if(((Editor) d).isNew) {
                        /// search free slot ...
                        int i = 0;
                        for(; i < data.length; i++) {
                            if(data[i] == null) break;
                        }
                        if(i < data.length)  {
                            /// ... and store the new object 
                            data[i] = ((Editor)d).getObject();
                        }
                    }
                    showOverview();
                }
                else if(c == exit) {
                    showOverview();
                }
            }
        }
        protected void destroyApp(boolean unconditional)
                throws MIDletStateChangeException {
    
        }
    
        protected void pauseApp() {
    
        }
    
    }
    

    I hope this helps, don't hesitate to ask ...