发信人: rampig(十倍市盈率) 
整理人: zjxyz(2002-04-10 19:09:07), 站内信件
 | 
 
 
发信人: javalover (欲下未下风悠扬), 信区: Java
 标  题: J2ME学习札记
 发信站: 北大未名站 (2001年10月17日22:22:58 星期三) , 站内信件
 
 (1)-----什么是J2ME?
     J2ME就是Java 2 Platform,micro Edition的缩写。J2ME是Java 2的一个组成部分,与J2
     SE、J2EE并称。根据Sun Microsystems,Inc.的定义:J2ME是一种高度优化的Java运行环境,针
     对市面上的大量消费类电子设备,例如Papers、cellular phones(蜂窝电话), screen-phones
     (可视电话?)、digital set-top boxes(数字机顶盒)、car navigation systems(汽车导航
     系统)等等。
     J2ME技术在1999年的JavaOne Developer Conference大会上推出。J2ME技术将Java语言
     的与平台无关的特性移植到小型电子设备上,允许移动无线设备之间共享应用程序。
 
 (2)----为了学习J2ME技术,我需要安装什么样的软件?
     1)、J2ME Wireless Toolkit
     J2ME Wireless Toolkit简称J2MEWTK,目前最新的版本就是1.0.3 Beta,J2MEWTK有什么用?打
     一个比方,J2MEWTK之于J2ME程序的开发,就相当于JDK之于Java程序的开发。J2MEWTK是由Sun
     公司开发的,你可以到Sun的网站去下载,这个工具和JDK一样,是完全免费的。
     2)、J2SE SDK 1.3
     J2SE SDK 1.3亦即JDK 1.3,JDK有什么用?相信学过Java语言的人都知道,我就不多写了,在安
     装J2MEWTK之前,你必须确保你的系统已经安装了一个可用的JDK。建议不要使用JDK 1.2和JDK 
     1.4,前者版本低,后者不稳定。
     3)、Tomcat 3.2.3/4.0
     Tomcat 3.2/4.0用作服务器软件,为J2ME手机提供服务。由于手机的资源有限,所以我们需要
     尽量将商业计算集中于服务器端完成,减小客户端的负担,所以要开发J2ME程序,一个服务器软
     件是少不了的。我采用JSP作为服务器端的解决技术,所以我选用的Web服务器是Tomcat。但是
     你也可以选用IIS+ASP、Apache+PHP。这个选择不是唯一的。
 
 (3)----开发环境安装
     第一步,安装JDK 1.3.0或者安装一个包含JDK 1.3.0的软件。我安装了Jbuilder 5.0,它所带
     的JDK是HotSpot 1.3.0_01 Client版。
 
     第二步,安装J2MEWTK 1.0.3 Beta,在安装的过程中,需要选择系统中JDK的安装目录,安装程序
     一般可以自动查出来JDK的安装目录,我们不用操心。
 
     第三步,安装Tomcat 3.2.3/4.0,Tomcat 3.2.3是最稳定的3.x系列,推荐使用。Tomcat 4.0刚
     刚发布了正式版,也不妨一试。Tomcat 3.2.3/4.0需要经过配置,才能够运行。
 
     第四步,测试Tomcat是否能够正常运行JSP程序。这一步很重要。
 
 (4)-----J2ME开发工具比较
     1)、J2MEWTK,这个工具在前文已经提到过,它是最基本的J2ME程序开发工具,免费,体积小,速
     度较快,完全遵守J2ME的各种规范。具有简单的IDE界面,易于上手,开发十分方便快捷,可以和
     Forte 3.0捆绑。J2MEWTK适用于初学者和已经达到很高水平的开发者。窃以为J2MEWTK+JDK+
     Editplus/UltraEdit是绝配。评语:重剑无锋,大巧不工。
 
     2)、VisualAge Micro Edition 1.4。这是IBM的产品,号称是J2ME开发领域的TOP 1,但是我用
     了半天,也没有看出好在那里。马上就删除了。窗口太复杂,不明所以,开发起来很难适应,速
     度和J2MEWTK一样,比较庞大,装了这个东西,你的C盘就要小心了,多了很多乱七八糟的文件,还
     注册了许多COM组件,典型的非绿色软件。评语:!#$#%$#$%$#%@$@#。
 
     3)、CodeWarrior for Java 6.0。这是Motolola的产品,功能十分强大,集成度很好,开发,调
     试,发布J2ME程序都很方便(还可以做一般的Java Program)。它的IDE和Visual Studio十分相
     似,很容易上手。CodeWarrior比较适合中等水平的开发者的使用。不过CodeWarrior不是免费
     软件,你只能够免费使用30天。评语:摩托罗拉CodeWarrior,随时随地J2ME。
 
     4)、Borland Jbuilder 5.0的Nokia Bobile版。没用过。评语:缺。
 
     上述分析,仅供参考,仅代表本人意见。
 
 5)------选择缺省的开发设备
     在开发J2ME应用程序之前,我们必须选择这些程序运行的平台,亦即开发出来的J2ME程序
     运行在那一种手机或者是移动设备上面。在开发的过程中,我们需要对J2ME应用程序进行测试
     ,当然了,自己拥有一款支持J2ME的手机是最好的,例如Motolola的i85s,但是这个要求不是每
     一个开发者都能够满足(我连手表都没有,更不用说手机了),因此,大多数的J2ME开发环境都提
     供了各种各样的手机、移动设备模拟器,你可以首先在手机模拟器上测试你的J2ME程序,开发
     完毕以后,再将程序交给专业的厂商(一般是移动设备提供商),由它们将程序载入手机中进行
     真实的程序测试。模拟器和真实的设备之间有一定的差别,但是你的程序只要在模拟器上通过
     了,那么问题不会很大。
 	
     J2MEWTK提供六种模拟器,分别是:Default Color Phone、Default Gray Phone、Minimum 
     Phone、Motolola i85s、PalmOS Device、RIM Java Handle。这些模拟器虽然外观不一样
     ,操作也不太一样,但是J2ME程序在其上运行的结果是不会有什么区别的,在真实的设备上也是
     没有什么区别的,这体现了Java的跨平台特性。你还可以自定义自己的手机模拟器,这在J2ME WTK的
     User Guide中有详细的描述。
     在开发过程中,选择何种模拟器是十分重要的,原则上来说,你为那一种设备开发程序
     ,就要使用那一种设备的模拟器。但是J2ME程序在不同的模拟器上的运行效果基本上是一致
     ,所以你也可以采用你自己喜欢的模拟器。我们推荐你选用RIM Java Handle模拟器作为开发
     的首选模拟器,因为它的屏幕很大,看起来很舒服(但是别忘了你的真实设备的屏幕大小)。
     在J2MEWTK中,可以设定缺省的模拟器,怎么设呢?从开始菜单选择J2MEWTK---->Default 
     Device Selection,在下拉列表框中选择模拟器的名字,然后单击OK按钮即可,J2MEWTK就会把
     这种模拟器认为是缺省的模拟器。你也可以在开发环境中每次手动选择模拟器,不过这样做显
     然比较麻烦。J2MEWTK在初始情况下,默认的模拟器是Default Color Phone,说实在话,我从
     来没有看见过这么难看的手机。
 
 6)-----创建项目
 	现在开始尝试开发J2ME程序。我的选择是Windows XP 2600 Professional+J2SE SDK 1.3.0+
     Tomcat 4.0+J2MEWTK 1.0.3Beta。从开始菜单中选择J2MEWTK---->Ktoolbar。Ktoolbar是
 	J2MEWTK提供的一个简陋的IDE工具。
     进入Ktoolbar以后,观察窗口,在菜单的下面有四个按钮,分别是:
 	New Project:创建一个新的项目。
 	Open Project:打开一个项目。
 	Setting:对当前项目的环境进行设置。
     Build:编译项目中的所有Java文件。
     Run:启动缺省的模拟器,将当前项目载入,运行。
     Clear Console:清除控制台输出。
     在上述按钮的下面,有一个下拉列表框,在这里你可以设置当前项目所使用的模拟器,这个
     设置可以覆盖缺省的模拟器。在此下拉列表框下面,是一个文本框,这就是所谓的控制台了。
     所有编译、运行信息都会在这个控制台中输出。你可以使用Clear Console按钮将控制台中的
     信息完全清除。
     现在来看看菜单。Ktoolbar的菜单极其简单,没有什么可说的。Project菜单的package菜单
     项的作用是将当前项目打包输出。这个菜单项特别有用,当你完成项目开发之后,使用这个菜
     单项可以产生一个jar文件,这样就完成的项目的初步发布。
     现在来创建一个新的项目,单击New Project按钮,或者是使用File菜单的同名菜单项。出现
     一个新窗口。这个新窗口有两个文本框,第一个文本框是Project Name,输入fancy。第二个文
     本框是MIDlet Class Name,输入fancy.test.HelloWorld。然后单击OK,又出现一个对话框,要
     你配置项目的环境,不理,单击OK按钮关闭该窗口,回到Ktoolbar的主窗口。经过上述步骤,你
     已经创建了一个名为fancy的J2ME项目。
 
 (7)-----J2MEWTK的目录结构
     安装J2MEWTK以后,你应该仔细浏览一下J2MEWTK的目录结构,这是一个很好的习惯。J2MEWTK
     的目录结构如下:
     appdb文件夹:里面有duke的一些靓照。
     apps文件夹:里面有J2MEWTK的一些例子程序,我们建立的项目文件也存放在里面。
     bin文件夹:里面全部是exe程序。
     docs文件夹:不用多说了,是地球人都知道。
     lib文件夹:存放MIDP API。
     wtklib文件夹:存放J2MEWTK用到的类库,以及一些资源文件,比如按钮的图标等等。
     在这些文件夹中,apps文件夹特别需要留意,这个文件夹有下列子文件夹:
     example:存放J2MEWTK的例子,侧重于图形方面,例子比较大,复杂,难看懂。
     lib:空,不知道放什么东西。
     tmplib:空,不知道放什么东西。
     UIDemo:存放J2MEWTK的例子,侧重于用户界面设计方面。例子不大,难度中等。
     fancy:这个文件夹原来是没有的,当我们创建fancy项目的时候,J2MEWTK自动为我们创建的文
     件夹。
     进入fancy文件夹,它里面又有很多子文件夹,如下所示:
     bin:存放项目的打包输出文件。
     classes:存放编译器产生的class文件。
     lib:空,不知道有什么用。
     res:存放资源文件,例如项目中用到的图片。
     src:存放项目的源代码。
     tmpclasses:存放编译器产生的class文件,是classes文件夹的镜像。
     tmplib:空,不知道有什么用,是lib文件夹的镜像。
     
 (8)-------HelloWorld!
   现在该是使用J2ME说Hello World的时候了。选择你最喜欢的文本编辑器,例如Editplus,
 输入下面的代码:
 package fancy.test;
 
 import javax.microedition.midlet.*;
 import javax.microedition.lcdui.*;
 
 public class HelloWorld extends MIDlet implements CommandListener 
 {
 	private Display display;
          private Form props;
    
 	private Command exitCommand = new Command("Exit", Command.EXIT, 1);
 
 	public HelloWorld() 
 	{
 		display = Display.getDisplay(this);
          }
 
 	public void startApp() 
 	{
 		props = new Form("Hello World");
 		props.append("Hello World!\n");
 		
 		props.addCommand(exitCommand);
 		props.setCommandListener(this);
 		display.setCurrent(props);
          }
 
 	public void commandAction(Command c, Displayable s) 
 	{
 		if (c == exitCommand) 
 		{
 			destroyApp(false);
 		    notifyDestroyed();
 		}	
          }
 
 	public void destroyApp(boolean unconditional) 
 	{
           }
 
 	public void pauseApp() 
 	{
 		display.setCurrent(null);
 		props = null;
          }
 
 }
     然后将该文件保存在J2MEWTK_HOME\apps\fancy\src\fancy\test目录下面,文件名为Hello
     World.java。注意:你需要在fancy\src目录下面创建fancy文件夹,然后再在fancy文件夹下面
     创建test文件夹。最后才保存HelloWorld.java文件。
     现在转到J2MEWTK的主窗口,单击Build按钮,编译整个项目,查看控制台的输出信息,一切无
     误,再单击Run按钮,运行此程序。运行效果如下图所示:(缺)
     
 (9)-------HelloWorld解释一
   要停电了,只好写道这里了。
   1) package fancy.test;
   这行代码声明当前类所在的包。这是有必要的。而且这个包名必须和src文件夹中的目录结
   构对应。
 
   2) 
   import javax.microedition.midlet.*;
   import javax.microedition.lcdui.*;
   这两行代码导入必要的Java包,这两个包的作用在后面会提及,这里就不多说了。
 
   3) 
   public class HelloWorld extends MIDlet implements CommandListener
   J2ME程序一般应该继承MIDlet,实现CommandListener。就如Applet必须继承Applet,可能实
   现Runnable接口一样。
 
   4)
   private Display display;
   private Form props;
   定义两个私有对象,Display代表屏幕,显示区域。Form是容器的一种。在J2ME程序中,不但
   有容器的概念,还有画布(Canvas)的概念。这个程序在Form容器中显示文本。
 
   5)
   private Command exitCommand = new Command("Exit", Command.EXIT, 1);
   声明一个Command对象。J2ME的事件处理机制和J2SE的事件处理机制不太一样。在J2ME程序
   中,必须预先定义一些Command对象,注册到程序中。当设备发生了某个事件,会产生相应的Co
   mmand对象,并把它传递给一个事件处理函数----commandAction(),由它对所产生的事件做统
   筹处理。
   
   
   6)
   public HelloWorld() 
   {
      display = Display.getDisplay(this);
   }
   这个是构造函数,函数内部,调用Display对象的静态方法---getDisplay(),获取屏幕对象,
   实例化display变量。这个调用是必要的。你可以在构造函数中做这个工作,也可以在startApp()
   方法中做这个工作。推荐在构造函数中完成。
 
   7)MIDlet程序的运行流程
     构造函数---->startApp()------>侦听事件,接受命令------->commandAction()方法----
     --->调用别的方法----------->如果是exit命令--------->pauseApp()--------->destroyApp()方法。
     实际上MIDlet程序的运行流程和Applet程序的运行流程差不多。
 
   8)
 	public void startApp() 
 	{
 		props = new Form("Hello World");
 		props.append("Hello World!\n");
 		
 		props.addCommand(exitCommand);
 		props.setCommandListener(this);
 		display.setCurrent(props);
           }
   这是startApp()方法。这个方法是父类的抽象方法,在子类中必须予以覆盖。首先实例化Form对象
   ----------props,Form的构造函数的参数(Hello World)就是屏幕的标题。Form对象
   是一容器,在里面可以包含别的东西,props.append(“…..”);的作用就是在这个容器中存放
   一个字符串。这个字符串会在屏幕中显示出来。
   接下来的三行代码分别做这样的工作:
   将Exit命令注册到Form对象(props)中,这样Form对象(props)可以对该命令作出响应。
   设置Form对象(props)的命令监听者。
   将Form对象设置为屏幕显示的对象。
   你可以试着注释掉这三行代码,再编译运行这个程序,看看会发生什么情况。
 
   9)
 	public void commandAction(Command c, Displayable s) 
 	{
 		if (c == exitCommand) 
 		{
 			destroyApp(false);
 		    notifyDestroyed();
 		}	
          }
    这个方法是事件处理的中枢,它接受各种命令,并对其进行分析,再分别调用合适的处理方法。
    在这个例子中,当接收到Exit命令以后,马上销毁程序,退出。
 
   10)destroyApp()方法的作用是退出程序并销毁程序对象。pauseApp()方法的作用是暂停程序
   ,并销毁容器对象或者是画布对象。手机屏幕将会是一片空白。
   
 (11)------J2ME的类库结构
     javax.microedition.lcdui:用户界面包,主要用于构造程序的用户界面。Command、Form都
     是这个包的类。
     javax.microedition.rms:这个包实现了对手机数据的存取功能。
     javax.microedition.midlet:这个包是MIDlet程序的声明周期包,主要定义了MIDlet类,MIDlet
     类是一个抽象类,里面声明了startApp()、destroyApp()、pauseApp()等抽象方法。
     javax.microedition.io:网络IO包。有HttpConnection接口和Connection接口、Datagram接口。
     java.io.*
     java.lang.*
     java.util.*
     上面这三个包属于J2ME核心包,J2ME中的核心包和J2SE中的同名核心包有些差别,主要是功能
     大大简化了,许多类、方法都没有了,只能实现一些最基本的功能。
 
 (12)---J2ME开发中的中文问题
 
       J2ME开发中有中文问题吗?可能有,但是我目前没有遇到。因为我没有手机,只能在模拟器上
     运行J2ME程序,真实的情况是什么样子我也不知道。在水木上有人说已经出现了中文问题,在
     模拟器上好好的,到了真正的手机上却是一团乱码。我现在也没有办法,只有在遇到的时候再
     补上这一节。我写的测试程序如下所示,这个程序是在HelloWorld.java的基础上改进而来的。
     
     package fancy.test;
     
     import javax.microedition.midlet.*;
     import javax.microedition.lcdui.*;
     import java.util.*;
     
     public class Poem extends MIDlet implements CommandListener 
     {
     	private Display display;
              private Form props;
     	
        
     	private Command exitCommand = new Command("Exit", Command.EXIT, 1);
     
     	public Poem() 
     	{
 		    display = Display.getDisplay(this);
         }
     
     	public void startApp() 
     	{
 		    props = new Form("影落寒潭的签名档");
 		    props.append("小楼一夜听春雨\n");
     		props.append("深巷明朝卖杏花\n\r");
     		props.append("虹虹的签名档\n");
 		    props.append("鸳鸯独宿何曾惯\n");
 		    props.append("化作西楼一缕云\n");
 		    props.addCommand(exitCommand);
 		    props.setCommandListener(this);
 		    display.setCurrent(props);
         }
 
     	public void commandAction(Command c, Displayable s) 
     	{
 	    	if (c == exitCommand) 
 		    {
 			    destroyApp(false);
 		        notifyDestroyed();
 		    }	
         }
 
 	    public void destroyApp(boolean unconditional) 
 	    {
         }
 
 	    public void pauseApp() 
 	    {
 		    display.setCurrent(null);
 		    props = null;
         }
     }
       使用普通的编辑器编辑好上述文件以后,保存为Poem.java,保存路径为src\fancy\test。然
     后在Ktoolbar中编译,一切无误之后,单击Setting按钮,出现一个配置窗口,选择MIDlets面板
     ,单击Add按钮,依次输入Poem、fancy.png、fancy.test.Poem三项。单击OK按钮,再单击OK按
     钮,关闭配置窗口,回到Ktoolbar的主界面,再次编译。一切无误之后,单击Run按钮运行程序。
     Poem的运行效果如下图所示。
     注意:每新编写一个程序,都要按照这个步骤进行配置,再编译运行,我以后就不再重复描述 这个步骤了。
     
 12)补-----运行效果图(无)
 
 (13)----查看系统属性
 
 请看下面的代码(Prop.java):
 package fancy.test;
 
 import javax.microedition.midlet.*;
 import javax.microedition.lcdui.*;
 import java.util.*;
 
 public class Prop extends MIDlet implements CommandListener 
 {
 	private Display display;
          private Form props;
 	
    
 	private Command exitCommand = new Command("Exit", Command.EXIT, 1);
 
 	public Prop() 
 	{
 		display = Display.getDisplay(this);
     }
 
 	public void startApp() 
 	{
 		props = new Form("System Properties");
 		props.append("Hello World!\n");
 		long time=System.currentTimeMillis();
 		props.append("current time:"+time+"\n");
 		
 		props.append("microedition.configuration:"+
             System.getProperty("microedition.configuration")+"\n");
             
 		props.append("microedition.profiles:"+
             System.getProperty("microedition.profiles")+"\n");
             
 		props.append("microedition.platform:"+
             System.getProperty("microedition.platform")+"\n");
             
 		props.append("microedition.locale:"+
             System.getProperty("microedition.locale")+"\n");
             
 		props.append("microedition.encoding:"+
             System.getProperty("microedition.encoding")+"\n");
             
 		props.append("java.version:"+System.getProperty("java.version")+"\n");//null
 		
 		props.append("java.vendor:"+System.getProperty("java.vendor")+"\n");//null
 		
 		props.append("java.vm.name:"+System.getProperty("java.vm.name")+"\n");//null
 		
 		props.append("java.vm.version:"+System.getProperty("java.vm.version")+"\n");//null
 		
 		props.append("os.name:"+System.getProperty("os.name")+"\n");//null
 		
 		props.append("os.arch:"+System.getProperty("os.arch")+"\n");//null
 		
 		props.append("os.version:"+System.getProperty("os.version")+"\n");//null
 		
 		props.append("user.name:"+System.getProperty("user.name")+"\n");//null
 		
 		props.addCommand(exitCommand);
 		
 		props.setCommandListener(this);
 		
 		display.setCurrent(props);
     }
 
 	public void commandAction(Command c, Displayable s) 
 	{
 		if (c == exitCommand) 
 		{
 			destroyApp(false);
 		    notifyDestroyed();
 		}	
     }
 
 	public void destroyApp(boolean unconditional) 
 	{
          }
 
 	public void pauseApp() 
 	{
 		display.setCurrent(null);
 		props = null;
     }
   }
   这个程序的作用是输出系统中各个环境属性的值。诀窍是使用System类的getProperty()方
   法。请注意,J2ME核心包的System类已经不支持getProperties()方法了,而且很多环境属性都
   不再支持了,比如java.version、java.vendor等等。
   
 (14)----查看内存利用情况
 
 请看程序(Memory.java):
 package fancy.test;
 
 import javax.microedition.midlet.*;
 import javax.microedition.lcdui.*;
 
 public class Memory extends MIDlet implements CommandListener 
 {
 	private Display display;
          private Form props;
    
 	private Command exitCommand = new Command("Exit", Command.EXIT, 1);
 
 	public Memory() 
 	{
 		display = Display.getDisplay(this);
         }
 
 	public void startApp() 
 	{
 		props = new Form("Runtime Information");
 		long total=Runtime.getRuntime().totalMemory();
 		long free=Runtime.getRuntime().freeMemory();
 		props.append("total memory:"+total+"\n");
 		props.append("free memory:"+free+"\n");
 		
 		props.addCommand(exitCommand);
 		props.setCommandListener(this);
 		display.setCurrent(props);
          }
 
 	public void commandAction(Command c, Displayable s) 
 	{
 		if (c == exitCommand) 
 		{
 			destroyApp(false);
 		    notifyDestroyed();
 		}	
          }
 
 	public void destroyApp(boolean unconditional) 
 	{
          }
 
 	public void pauseApp() 
 	{
 		display.setCurrent(null);
 		props = null;
          }
 
 }
   这个程序的诀窍是利用Runtime类的totalMemory()方法以及freeMemory()方法。J2ME中的
 Runtime类不再具有执行外部程序的功能了,这是很显然的。 | 
 
 
 |