关于 midp:关于 Java ME 应用程序中堆栈发生了什么的基本查询

Basic query about what's going on with the stack in a Java ME app

我以 Java SE 背景(基本上没有 GUI/ActionListener 经验)来到 Java ME,但由于缺少 main() 方法,我仍然有点迷失方向。也许我应该说我正确地学习了 Java SE,但我试图通过谷歌搜索大量"Java ME for dummies"页面来自学 Java ME,这并不理想。我曾以为我会侥幸逃脱,但现在不太确定了。

为了让 Java ME 脚本启动并运行,我为基类编写代码,但没有静态 main() 方法。相反,我让类扩展 MIDlet,然后编写方法 startApp()、pauseApp() 和 destroyApp()。不过,这些方法似乎不是静态的(从某种意义上说,我在这里查看的"hello World"应用程序并未将它们创建为静态方法)。

那么第一个问题:当我开始在手机上运行我的 MIDlet 时,是否真的在堆栈上创建了一个基类的实例?

在那之后,我更加困惑了。大概我的第一个问题的答案是肯定的,我可以将实例称为"this"。现在在 StartApp() 中,我将创建一个表单并显示它。所以我的部分代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class TestMidlet extends MIDlet implements CommandListener {

    List mainForm;
    Command comSelect;

    protected void startApp() throws MIDletStateChangeException {

        mainForm = new List("Menu",List.IMPLICIT);

        mainForm.append("this one?",null);
        mainForm.append("or this one?",null);

        comSelect=new Command("Select",Command.ITEM,1);
        mainForm.setSelectCommand(comSelect);
        mainForm.setCommandListener(this);

        Display.getDisplay(this).setCurrent(mainForm);
    }

    public void commandAction(Command c,Displayable d) {
        // we will end up here when the user makes a selection in mainForm.
    }

当 MIDlet 启动时,我怀疑在堆栈上创建了一个 TestMidlet 实例。然后运行 ??startApp() 方法,该方法创建一个表单并将其显示在屏幕上。现在在我天真的眼里,接下来发生的是 startApp() 现在用完了要执行的命令,然后结束。

第二个问题:我是否正确假设 (a) startApp() 确实完成但 (b) TestMidlet 的实例由于某种原因不能用于垃圾收集,因为表单通过 commandListener 以某种方式使其保持活动状态?在这一点上,我真的不清楚是否有当前正在运行的堆栈。据推测,关键是未命名的 TestMidlet 本身就是一个 CommandListener,因此仍然很忙,因此尽管我看不到任何引用它的东西,但不想用于垃圾收集。

最后,当用户在表单中做出选择时,这个未命名的 TestMidlet 实例会在其 commandAction() 方法开始运行的意义上弹回行动?特别是我仍然可以在它的 commandAction 方法中访问这个神秘的未命名的 TestMidlet 实例,使用"this"?

这一切我都说清楚了吗?


  • 当您开始在手机上运行 MIDlet 时,会以与 new Object() 相同的方式创建 TestMidlet 实例
    您可以将上述实例称为 this

  • startApp() 是一个典型的"步骤方法",根据模板方法模式
    鉴于您的 Java SE 背景,我希望这听起来很熟悉。这里真的没有魔法 - 将其视为在运行生命周期序列的过程中调用 startApp() 的某个框架,这对您来说是不可见的。如果您对更多细节感兴趣,请在网上搜索 MIDlet 生命周期之类的内容。

  • startApp 的最后一条语句中,这个方法确实完成了——你就在这里。但是,实际上并没有什么神奇的事情发生——TestMidlet 实例还活着并且运行良好,在"MIDP 框架"下运行,直到用户停止您的应用程序或您的代码在 TestMidlet

    的实例上调用 notifyDestroyed()

  • 关于垃圾回收,你可以安全地应用从 Java SE 获得的一般理解,保存缺少的方法 Object.finalize()(通常准备 MIDP 缺少一些你在 Java SE 中习惯的其他方法和类)

  • 这个未命名的 TestMidlet 实例在它的 commandAction() 方法开始运行的意义上弹回动作 - 如果您正确设置命令侦听器并添加命令。特别是您仍然可以在其 commandAction 方法中访问这个神秘的未命名的 TestMidlet 实例,使用 "qualified this" JLS 15.8.4 Qualified this like TestMidlet.this

  • 鉴于您对所有这些命令和侦听器感到困惑,我建议您在实验代码中去掉实现 CommandListener,大致如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    public class TestMidlet extends MIDlet {

        List mainForm;
        Command comSelect;

        protected void startApp() throws MIDletStateChangeException {

            mainForm = new List("Menu",List.IMPLICIT);

            mainForm.append("this one?",null);
            mainForm.append("or this one?",null);
            mainForm.append("Exit",null);

            comSelect=new Command("Select",Command.ITEM,1);
            mainForm.addCommand(comSelect); // note addCommand here
            mainForm.setSelectCommand(comSelect); // convenient thing BTW

            mainForm.setCommandListener(new CommandListener() {
                public void commandAction(Command c,Displayable d) {
                    // we'll end up here when the user makes a selection in mainForm.                  
                    List list = (List)d;
                    // note d refers to mainForm here, that's why it's OK to cast above
                    if (list.getString(list.getSelectedIndex()).equals("Exit")) {
                        // if user selected exit
                        TestMidlet.this.notifyDestroyed(); // exit the midlet
                    }
                }
            });
            // display the form
            Display.getDisplay(this).setCurrent(mainForm);
            // startApp finishes here
        }
    }

    Do I have all this straight?

    不完全是。鉴于您的问题,您的"Java ME for dummies"页面的级别似乎已经过大,因此是时候切换到更严肃的资源了。

    值得检查的是:

    • 学习路径:MIDlet 生命周期 - SDN 教程
    • MIDP 2 (JSR 118) 规范。获取 PDF 版本,跳过方法和类的详细信息以进行介绍性阅读。
    • 维基百科上的 Java ME 文章,让您知道除了 MIDP 之外还有什么

    请记住,有一个更新版本的 MIDP 规范 - JSR 271,尽管我不建议您深入研究它,除非您明确知道您的目标是这个版本。

    您遇到的一些困难来自于您的背景基本上没有 GUI/ActionListener 经验。准备好适应"UI 风格思维"需要一些时间。如果您还没有阅读它,请查看 java.net

    上的 J2ME 教程,第 2 部分:使用 MIDP 2.0 的用户界面