分享
 
 
 

教你一招:优化J2ME程序大小的方法

王朝java/jsp·作者佚名  2008-05-19
窄屏简体版  字體: |||超大  

要把J2ME程序与J2SE程序区分开来,其依据就是J2ME运行所处的受限环境。多数J2ME系统的主要受限条件就是可以存储和运行程序所需内存的大小。例如,许多MIDP设备限制应用程序的尺寸不大于50K,这远远不及Server端J2SE运行环境下那些成兆的程序。实际应用中,程序会很容易超出这些限制条件。通过本篇您将学到一些减小程序尺寸大小的技巧,并在下面的例子中实践这些技术。这个例子MIDlet仅仅显示一个文本框并在其内容改变时发声。

package com.j2medeveloper.techtips;

import javax.microedition.lcdui.*;

public class BeforeSizeOptimization extends

BasicMIDlet {

public static final Command exitCommand =

new Command( "Exit",

Command.EXIT, 1 );

public BeforeSizeOptimization(){

}

protected void initMIDlet(){

getDisplay().setCurrent( new Mainform() );

}

public class Mainform extends form {

public Mainform(){

super( "Mainform" );

addCommand( exitCommand );

append( textf );

setCommandListener( new CommandListener(){

public void commandAction( Command c,

Displayable d ){

if( c == exitCommand ){

exitMIDlet();

}

}

}

);

setItemStateListener(

new ItemStateListener() {

public void itemStateChanged(

Item item ){

if( item == textf ){

AlertType.INFO.playSound(

getDisplay() );

}

}

}

);

}

private TextField textf =

new TextField( "Type anything", null,

20, 0 );

}

}

虽然这个MIDlet在此仅作为一个例子,但使用的尺寸优化技巧可以适用于任一J2ME的profile上。

注意,上面的MIDlet类需要下面的辅助类:

package com.j2medeveloper.techtips;

import javax.microedition.lcdui.*;

import javax.microedition.midlet.*;

public abstract class BasicMIDlet extends MIDlet {

private Display display;

public BasicMIDlet(){

}

protected void destroyApp( boolean unconditional )

throws MIDletStateChangeException {

exitMIDlet();

}

public void exitMIDlet(){

notifyDestroyed();

}

public Display getDisplay(){ return display; }

protected abstract void initMIDlet();

protected void pauseApp(){

}

protected void startApp()

throws MIDletStateChangeException {

if( display == null ){

display = Display.getDisplay( this );

initMIDlet();

}

}

}

用J2ME WTK打包时,本例子MIDlet占用4K空间。

减小尺寸的首要步骤就是通过修正程序的功能实现来去掉多余的类。程序的所有功能确实必须都实现吗?用户可以不需要这些“附属功能”吗?要设计尽可能小的程序,这里的MIDlet例子已经相当小了。

第二步就是深入考察程序定义的内部类,特别是匿名类。记住,每个类文件都有一定量的与之相关的系统开销。即便最普通的类也有系统开销。

public class foo {

// nothing here

}

编译上边的类,生成的类文件大约200byte大小。比如实现一个事件监听器,就是对匿名类的常见使用。在例子MIDlet中就定义了两个此类的监听器。接下来进行的最简单的优化就是,让主MIDlet类实现CommandListener和ItemStateListener接口,并把监听器代码移至此处。记住,多个对象可以使用同样的监听器。必要时,可以使用传递至commandAction和itemStateChanged方法的参变量来区分它们。

内部类也可使代码过大,因为编译器必须生成特殊的变量和方法,以便内部类可以访问包含它们的类的私有内容。请参考内部类的规范以获取更多信息。

第三步,尽量使用现有的类。例如,基于CLDC的profile没有构造集合类,所以我们可以用内建的Hashtable和Vector类来实现之。构造MIDP程序时也可采用此法。例子MIDlet中定义了一个form字类来生成主表,可以容易的如下直接生成:

mainform = new form( "Mainform" );

mainform.addCommand( okCommand );

mainform.setCommandListener( listener );

这里没有正确或者错误的答案,只是要推敲。

第四步就是破坏程序的继承关系。你也许把相关的代码放到一个或多个抽象类中,这是OOD中为提高程序间代码重用的推荐做法。虽然破坏继承关系与你所学知识相违背,但简化的继承关系更有意义。特别的,当你的的抽象类?D?D可能来自其他项目?D?D仅仅被继承一次时,破坏继承关系的结果不言而喻。例如,例子MIDlet继承了BasicMIDlet类,但两者合并为一个类。

第五步就是要缩短名字长度,如包名、类名、方法名和数据元素名。看起来有些蠢,但一个类文件确实包含太多的符号信息。缩短各量的名字可以缩小生成的类文件尺寸。这种节省不会特别明显,但多个类中进行总加的结果还是可观的。包名对减小尺寸来讲特别合适。MIDP程序是完全自我包容的,完全可以不使用包名,因为在手持设备上包名根本不可能与其他类名冲突。例子MIDlet中,可以把com.j2medeveloper.tchtips包名去掉。

注意,一般来讲,缩短名字不需要手工去做,要用一个“混淆器”去做。“混淆器”的主要功能是“隐藏”程序代码,使之不能通过反编译读出。它的副作用是减小了程序的尺寸。因为隐藏过程主要通过更改方法和数据成员的名字来完成。有一个开源的混淆器称为RetroGuard,可以免费从http://www.retrologic.com得到。也有一些商业包可用。(当为基于CLDC的profile混淆时,记得在预校验之前混淆,否则混淆器将使类文件中的预校验数据失效。)

最后,深入数组的初始化。(例子MIDlet没有做数组初始化,但对程序来说初始化是重要的一步) 在编译时,一个数组初始化声明如下所示:

int arr[] = { 0, 1, 2, 3 };

而实际生成代码的过程如下所示:

arr[0] = 0;

arr[1] = 1;

arr[2] = 2;

arr[3] = 3;

这个过程可以通过使用Java 2 SDK中附带的javap工具把二进制代码反编译成类文件去看(使用-c选项)。也许你会诧异于看到的内容,特别当你希望看到的是一排排二进制常数时。有两种方法可以让你看不到反编译的程序代码,(1)把数据编码为字符串,运行时解码之,或者(2)把数据存为二进制文件并与程序打包,用类装载器的getResourceAsStream方法在运行时存取之。

以上只是一些指导性的方法,对每个J2ME程序而言,这里没有具体到步骤。但是多数方法可以应用的本例。优化后的MIDlet如下所示:

import javax.microedition.lcdui.*;

import javax.microedition.midlet.*;

public class ASO extends MIDlet

implements CommandListener,

ItemStateListener {

private Display display;

private form mainform;

private TextField mainformTF =

new TextField( "Type anything", null,

20, 0 );

public static final Command exitCommand =

new Command( "Exit",

Command.EXIT, 1 );

public ASO(){

}

public void commandAction( Command c,

Displayable d ){

if( c == exitCommand ){

exitMIDlet();

}

}

protected void destroyApp( boolean unconditional )

throws MIDletStateChangeException {

exitMIDlet();

}

public void exitMIDlet(){

notifyDestroyed();

}

public Display getDisplay(){ return display; }

protected void initMIDlet(){

mainform = new form( "Mainform" );

mainform.addCommand( exitCommand );

mainform.setCommandListener( this );

mainform.setItemStateListener( this );

mainform.append( mainformTF );

getDisplay().setCurrent( mainform );

}

public void itemStateChanged( Item item ){

if( item == mainformTF ){

AlertType.INFO.playSound( getDisplay() );

}

}

protected void pauseApp(){

}

protected void startApp()

throws MIDletStateChangeException {

if( display == null ){

display = Display.getDisplay( this );

initMIDlet();

}

}

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有