3

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.

eddy
  • 4,373
  • 16
  • 60
  • 94
  • I once did a very small project, but being a very small project I ended up putting everything inside a single MIDlet. – Axel Jun 09 '14 at 11:14
  • Yeah. I'd do that too if I had just a couple of screens. – eddy Jun 09 '14 at 11:15

2 Answers2

2

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 ...

Gregor Ophey
  • 817
  • 6
  • 12
  • 1
    Thank you Gregor. I really appreciate your suggestions, but do you think you could clarify these two points: 1) if the commandAction is something like a controller and screens are like views, what would be the equivalent to models?? 2) How do you control screens located in independent .java files?? Do you think you could explain to me point 2 in general terms? – eddy Jun 11 '14 at 01:06
  • @Thank you Gregor. That would help me a lot. I'll be looking forward to it. :) – eddy Jun 11 '14 at 21:21
  • @eddy : I just added the code to the existing answer. I hope it's clear and helps a bit – Gregor Ophey Jun 11 '14 at 21:28
  • Thanks @Gregor. I didn't comment earlier because I was really busy at work I didn't have the time to sit down and take a closer look at your code.But now that I have reviewed your code I must say I find it AMAZING!! I think it might be what I was looking for, but I have a couple of questions, so I think I'm gonna take you at your word – eddy Jun 16 '14 at 11:56
  • **First question** : Where would you put the code for applications threads? Personally, I use a separate thread for operations in which I have to deal with HTTP connections and RMS, but I'm not sure where these applications threads would fit in your MVC pattern. – eddy Jun 16 '14 at 12:08
  • The **second question** is about the Overview List. In that List you only show names of an array of `DomainObject`s. Without storing another property in the List, how do you then relate a `name` from the List with its corresponding `DomainObject` so that when I select the **Edit** command , all the properties of that `DomainObject` (name,street,phone) are shown in the `Editor` Form??? I really hope I'm not asking too many questions. Thanks again. – eddy Jun 16 '14 at 12:55
  • @eddy : regarding your second question see [here](http://stackoverflow.com/questions/24215603/j2me-does-a-list-have-any-property-to-keep-track-of-key-that-identify-the-it/24220121#24220121) – Gregor Ophey Jun 17 '14 at 20:51
  • I'm accepting your answer.I really appreciate all the help you've been giving me lately and regarding my second question, I'm asking another question for that topic, I really hope I can have your help there too. – eddy Jun 22 '14 at 16:14
  • 1
    @eddy : thanx for accepting my answer. I'm still thinking about the thread question, but are a little short on time right now. Basically I would suggest to have the thread initiated from the MIDlet and also have callback methods for thread completion in the MIDlet, too. That way, the threads tie into the controller and the controller can decide how to react. – Gregor Ophey Jun 22 '14 at 19:25
1

I'm developing now at work a J2ME app with 10+ of screens adn i use only one MIDlet for my project. I use LWUIT for my UI purposes but you don't have to

every screen extends the Form class, and at the MIDlet i have a screen switching method that looks like this:

public class ExampleMIDlet extends MIDlet {
    private J2meServerGateway gateway;
     .....
    public void changeScreen(Form form) {
        form.show();
    }
}

every form has the MIDlet as parameter and uses the changeScreen method to switch to the next one.

most of the logic is in the forms and i also have an interface that i called J2meServerGateway that separates the view logic (input checks, and handling the result) and the actual calls to the server.

public class BackupForm extends Form implements ActionListener{
  private CloudBackupMIDlet midlet; // as parameter in the constructor
    ......
    public void actionPerformed(ActionEvent ae) {

        if (ae.getSource().equals(signupButton)) {
            doSomething(firstField.getText(), secondField.getText());
        }
    }

    private void doSomething(String st1, String st2) {
      midlet.getGateway().callServer(st1, st2); 
      midlet.changeScreen(new OtherForm(midlet));

    }
}

the J2meServerGatewayImpl is the controller, and uses the model - the objects, the parsers etc...

public class J2meServerGatewayImpl implements J2meServerGateway {
    ......
    public void register(String email, String phone,int password) throws IOException,
        ApiException {
        String params = ...//params
        String resultStr = sendPost(url, params);///actual server call
        //parsing logic etc...
}

hope that it helped

arseny
  • 396
  • 2
  • 13
  • Thanks you @arseny. I hope you don't mind me asking, but do think you could share the simplest example(at least the more relevant parts) in which you apply what you explained in your answer. It would really help me, as I'm in the learning process and one of the things that worry me most is how to organize my application so it would be easy to mantain. – eddy Jun 11 '14 at 17:55
  • added some more code to show my application structure hope that it clarifies some things – arseny Jun 12 '14 at 08:09