更新 Java ME 应用程序

作者:Vikram Goyal

了解更新 Java ME 应用程序的文本、图像和源代码是多么轻松。

2011 年 12 月发布

下载:

下载Java ME

下载NetBeans IDE

下载示例代码 (Zip)

简介

更新 Java Platform, Micro Edition (Java ME) 应用程序包括更新静态数据(如文本和图像)以及更新应用程序的代码组件。在本文中,我将开发一个示例应用程序来演示如何更新应用程序。

本文首先讲解基本知识,即更新纯文本字符串,然后讲解更新图像。最后,文章将介绍更新核心应用程序文件的最简便的方法,Java ME 让这一工作变得非常轻松。不过,这种轻松可能是以额外的网络流量为代价。

:可以从这里下载本文所述应用程序的完整源代码。

应用程序流

图 1 显示运行中的示例应用程序。

图 1. 示例应用程序

图 1. 示例应用程序

该应用程序有两个元素:基本文本字符串和图像。选择 Menu 将显示可以执行的三个操作,如图 2 所示。

图 2. 可能的操作

图 2. 可能的操作

Update Text 菜单项将检查后台服务器以确定是否有更新可用于应用程序文本部分。Update Image 将检查图像是否需要更新。最后,Update Code 将更新整个应用程序 — 文本、图像和底层代码。

下面我们就开始吧!

编写布局代码

该应用程序是一个包含三个基本命令和两个可视化组件的简单 MIDlet。我们在构造器中设置了基本显示元素并与命令挂钩,如清单 1 所示。

  public MyGreatApp() {
    
    // set up the basic MIDlet with the display and the elements
    display = Display.getDisplay(this);    
    
    form = new Form("My App");    
    
    // we start with a blue square and a simple string of text
    text = new StringItem("", "My starting text");
    try {      
      image = 
        new ImageItem(
              "", 
              Image.createImage("/blue_square.jpg"), 
              Item.LAYOUT_CENTER, 
              "");
    } catch (IOException ex) {
      handleError(ex);
    }    
    
    exitCommand = new Command("Exit", Command.EXIT, 2);
    
    updateTextCommand = new Command("Update Text", Command.ITEM, 1);
    updateImageCommand = new Command("Update Image", Command.ITEM, 1);
    updateCodeCommand = new Command("Update Code", Command.ITEM, 1);
    
    // add the commands etc
    form.append(text);
    form.append(image);
    
    form.addCommand(exitCommand);
    form.addCommand(updateTextCommand);
    form.addCommand(updateImageCommand);
    form.addCommand(updateCodeCommand);
    
    form.setCommandListener(this);   
    
  }

 

清单 1. 设置显示元素

此代码没有什么特别的地方。它创建一个 Form,然后向该 Form 添加两个可视化元素:StringItem 和 ImageItem。这些是我们要更新的元素。

然后添加各种命令:Exit 和三个更新命令(UpdateText、UpdateImage 和 UpdateCode)。注意,Exit 命令设置为与更新命令不同的级别,因此当您选择 Menu 时更新命令是组合在一起的。

最后,当前 MIDlet 设置为所有命令的命令监听器,使得它可以处理回调。下面来看看,为了更新文本、图像和代码,我们需要做哪些工作。

编写命令处理程序代码

编写此 MIDlet 的命令处理程序代码时要记住的最重要的一点是,所有命令处理工作均应在一个单独的线程中完成,这样在执行潜在的负担较重的网络调用时不会阻塞主线程的操作。

清单 2 显示处理 UpdateText 命令的代码:

    if(c == updateTextCommand) {
      new Thread() {
        public void run() {
          ContentConnection cc = null;
          DataInputStream dis = null;
          try {
            cc = 
              (ContentConnection)Connector.open(
                "http://localhost:8080/updatedText.txt");
            int size = (int)cc.getLength();
            dis = cc.openDataInputStream();
            byte[] data = new byte[size];
            dis.read(data);
            String newText = new String(data);
            
            // found some text, and it is updated - so update the screen
            if(newText != null && !newText.equals(text)) {
              text.setText(newText);              
            }
          } catch(IOException ioex) {
            handleError(ioex);
          }
        }
      }.start();
    }

清单 2. 用于处理 UpdateText 命令的代码

当此代码的命令处理程序启动时,它创建一个新线程并连接服务器(用于保存文本、图像和代码文件的服务器)。

此时,我们只关注检查基于文本的更新,因此使用 ContentConnection 类(而不是通常的 HttpConnection 类)。借助于这个类,我们检查服务器上是否存在 updatedText.txt 文件。如果找到这个文件,则使用 DataInputStream 将其读取到一个字节数组并转换成字符串。在任何阶段,如果发生错误,将由错误处理程序来接管。

如果找到该文件,读取其内容后发现内容与现有文本不同,则修改 StringItem 中的文本。瞧!我们已经更新了文本!图 3 显示运行 UpdateText 命令之后的 MIDlet。

图 3. 运行 UpdateText 命令之后的 MIDlet

图 3. 运行 UpdateText 命令之后的 MIDlet

下面我们看看如何更新图像。更新图像与更新文本大同小异。清单 3 显示如何完成这一工作。

    if(c == updateImageCommand) {
      new Thread() {
        public void run() {
          HttpConnection cc = null;
          DataInputStream dis = null;
          try {
            cc = 
              (HttpConnection)Connector.open(
                "http://localhost:8080/red_square.jpg");
            int size = (int)cc.getLength();
            dis = cc.openDataInputStream();
            byte[] data = new byte[size];
            dis.read(data);  
            
            // found an image - update it
            if(size > 0) 
              image.setImage(Image.createImage(data, 0, data.length));
          } catch(IOException ioex) {
            handleError(ioex);
          }
        }
      }.start();
    }

清单 3. 用于更新图像的代码

如您所见,我们使用 HttpConnection 类更新图像,而不是使用 ContentConnection。如果找到一个图像且其大小大于 0,则使用 DataInputStream 实例将其下载到字节缓冲区。我们使用 Image.createImage() 方法在内存中创建此图像,然后更新 ImageItem 以使用此新图像。

我们希望服务器上的更新进程仅在更新可用的情况下才获取文本文件或图像文件。这将是一个脱机过程,是更新例程的一部分。我们可以修改代码以通知用户没有更新可用,而不是让错误处理程序来处理。

最后,我们来看更新过程的一个最轻松的部分。即更新核心代码本身(或者说,更新整个 MIDlet 及其关联文件)。为什么说这是最轻松的部分呢?因为通过使用一个内置函数,可以请求 MIDlet 更新自身。当您对代码及关联逻辑进行了多次修改且因此需要更新非静态数据时,这将非常有用。缺点是更新过程可能大量占用网络。

要更新代码,请使用以下代码段:

    if(c == updateCodeCommand) {
      try {
        this.platformRequest("http://localhost:8080/UpdateArticle.jad");
      } catch (ConnectionNotFoundException ex) {
        handleError(ex);
      }
    }

我们使用方法 platformRequest(String) 更新代码本身。此方法由 MIDlet 类提供,用于请求运行它的设备来处理提供的 URL。请注意,它不并全然用于更新应用程序/MIDlet 本身,而是用于由关联设备处理 URL 的通用传输。例如,如果此方法是使用图像的 URL 调用的,则处理设备将需要调用图像查看器来查看该 URL 提供的图像。

通过提供一个以 .jad 结尾的 URL(本例中为 http://localhost:8080/UpdateArticle.jad)并使文件名与当前安装的应用程序相同,设备即了解该请求是要更新应用程序本身。如果找到 .jad 文件(及关联的 .jar 文件),并确定它是有效的,设备将自动启动下载/安装/更新周期,无需代码本身的任何干预,如图 4 所示。

图 4. 更新应用程序

图 4. 更新应用程序

当然,需要用户干预来确认更新过程并回答所有更新前问题,如图 5 所示。

图 5. 用户必须授权批准该更新

图 5. 用户必须授权批准该更新

一旦用户授权批准该更新,设备将下载并更新代码。此过程的发生不再需要用户和原始 MIDlet 的其他干预。一旦更新完成,将从设备删除旧的 MIDlet 并安装新的 MIDlet。安装之后,设备将确认用户是否希望启动新的 MIDlet。

总之,MIDlet 类的 platformRequest(String) 方法使应用程序开发人员可以轻松地为应用程序提供一种内置的更新机制。

总结

如果您不需要更新应用程序的整个源代码,可使用 javax.io 程序包内提供的连接类(如 ContentConnection 和 HttpConnection)来更新静态数据(如文本和图像)。

另一方面,如果您需要提供一种更新整个源代码的机制,请确保在服务器上遵循有效的更新过程,并使用 platformRequest(String) 通过以 jad 结尾的 URL 来提供更新。然后设备的接口将确保通过删除旧 MIDlet 并安装新的更新版本来应用更新。

另请参见

关于作者

Vikram Goyal 是 Apress 出版的《Pro Java ME MMAPI:Mobile Media API for Java Micro Edition》一书的作者。该书介绍如何向支持 Java 技术的手机添加多媒体功能。Vikram 还是《Jakarta Commons Online Bookshelf》一书的作者,他还帮助管理免费的 craft projects 网站