对于J2ME开发者来说,模拟器给我们带来了很多方便,比如可以在模拟器中调试程序以及很方便的察看程序的效果,但是模拟器也给我们带来了一些问题,比如模拟器实现的bug等等,所以进行真机测试是必须的。
1、为什么要进行真机测试?
因为模拟器程序可能存在bug,以及真机的性能有限,所以必须进行真机测试。
2、如何将程序传输到机器中?
将程序传输到机器中有如下方式:
a) OTA下载
b) 使用数据线传输
c) 红外传输
d) 蓝牙
3、 真机测试主要测什么?
a) 程序的功能
b) 程序的操作性,是否易操作
c) 程序的大小,比如Nokia S40系列的手机大部分接受的最大文件尺寸为64K
d) 程序运行速度,速度是否可以忍受。
以下就是各个机型Bug的汇总:
品牌 |
机型或系列 |
屏幕 |
Bug列表 |
Nokia |
S40 |
1. 按键会有延迟,中断后原线程还会在后台继续运行直到调用repaint,内存开销不当会死机 2. 在S40SDK和真机中,使用RecordStore.deleteRecord(id)以后,枚举工作不正常 |
|
S60 |
1. 表现为java应用中如果使用了Class.getResourceAsStream("本地文件") 无法释放其占用的内存,是的,没有任何办法,无论是调用获得的的InputStream实例的close()或将其设为null,甚至显式强制 System.gc(),都没有效果。结果就是至少和本地文件同尺寸的内存成为了无法回收的垃圾。这个问题还影响到以 Class.getResourceAsStream()为基础的Image.createImage() 这个bug可以上溯至2003年,甚至更早。这个bug据说在新的S60上已经解决了。但是Nokia3230(4.0526.2ch)、 Nokia7610(6.0525.0ch)都存在这个问题。对于这些个有问题的机型,在java程序中是无法完美解决这个问题的,只能尽量避免。比如集中、统一载入资源,永不释放(也就是说,尽量控制泄漏的次数)。当然,这会对已有代码造成很大影响。毕竟手机java应用是内存受限系统的典型,大多数情况下,珍贵的内存中只保留需要的资源。 2. NokiaS60模拟器异常退出,模拟器自动关闭,没提示任何错误,使用了Nokia UI API中的灯光或振动控制,而Nokia S60部分机型和对应的模拟器不支持这两个特性 3. 旋转后,并以clip的方式向缓冲上贴图,clip无效 4. 无法创建透明muttable Image 5. 不能每帧调用 System.gc(),否则严重降低fps 6. 运行J2ME程序的时候出现“不能运行应用程序”的错误,一般都是内存不足引起的,但今天遇到这样的错误,却发现是另一个原因。即当使用nokia的UI API,DirectGraphics的drawImage时,如果旋转参数设置不当,也会出现“不能运行应用程序”的错误 7. Nokia S60 IO操作内存泄漏不可不察,其实这个问题是由S60的getResourceAsStream方法内存泄漏的bug引起的,由于每次切换地图时io操作都要读取大量数据,内存泄漏积累到一定程度就引起了“存储已满”,白屏,死机,进而会引起null pointer异常等。解决方法是尽量减少io操作的次数。如果内存够大就一次将资源读入 8. 不要在在主while循环中调用destroyApp,而改成检测一个标志,退出主循环后再调用destroyApp 9. 不同机型对于translate 和 setClip的处理不一样。在Nokia N-Gage QD等机型中,setClip是相对于translate以后的坐标计算的,而在Nokia 6600,6670等机型中,setClip不受translate的影响,永远只相对于屏幕左上角(0,0)点计算。所以如果在Nokia6670中,使用先translate再setClip的方法画子图,则会出现错误。为了统一代码,在NokiaS60中不要使用translate,即使使用,两次 translate之间不要进行setClip 10. DirectGraphics.fillTriangle调用有点问题,有时会出现跳出程序的情况,去除后没有问题。不知是机型的特例还有整个机型的BUG 11. java获取网络数据的永不ready的代码:while(InputStream.ready()) { InputStream.read() } 12. 同时播放声音在S60模拟器上可以运行,但是真机不支持 13. 在S60 1.0设备中,如果MIDlet在后台运行时,MIDI声音不停止 14. 在S60 1.0设备中,当正在运行的MIDlet被系统Screen隐含调用的类选择显示屏幕时有问题 15. 在S60 1.0设备中,Item.getLable()方法在ChoiceGroup中无法返回正确的label 16. 在S60 1.0设备中,Date对象无法返回当前时间 |
||
S60 MIDP1.0 |
176x208 |
1. 3650机型:setClip和drawRegion搭配不能正确设置裁减框 2. 3650机型:频繁I/O操作会死机,应尽量在游戏初始化时将数据一次读入 3. N-Gage机型:在背景缓冲上setClip和drawRegion搭配完全不能设置裁减框声音播放有问题 4. N-Gage机型:声音播放有问题,建议在I/O操作等跟系统底层有关调用之后再播放声音 5. N-Gage机型:Image.getGraphics()方法在不同的软件版本中工作不同,该方法无法在新版本的7650、3650和N-Gage中正常工作。即这些机器中无法实现双缓冲技术 6. N-Gage机型:无法控制背景灯和震动 |
|
S60 MIDP2.0 |
176x208 |
1. 6600机型:调用readFully不能按指定字节数读取,readByte代替 2. 6600机型:setClip和drawRegion搭配在欧版6600上不能正确设置裁减框,导致绘图错误 3. 6600机型:Nokia官方Konwn Issuse已经确认调用readFully不能按指定字节数读取,解决方法Known Issuse上有,另外一种就是用readByte代替。setClip和drawRegion搭配在欧版6600上不能正确设置裁减框,导致绘图错误,港版无此问题,解决方法自己想 4. 6600机型:setClip和drawRegion搭配不能正确设置裁减框。3650频繁I/O操作会死机,应尽量在游戏初始化时将数据一次读入 5. 6681机型:频繁I/O操作会死机,应尽量在游戏初始化时将数据一次读入 6. 6681机型:使用2.0的drawRegion会造成内存泄露,尽量减少使用翻转,尤其是画地图时应尽量使用1.0的drawImage来实现 |
|
S40 V1 |
128x128 |
1. 按键会有延迟,中断后原线程还会在后台继续运行直到调用repaint,内存开销不当会死机 |
|
Nokia |
N7370 |
240x320 |
1. font.getBaselinePosition()方法返回的值是错误的 |
N7610 |
176x208 |
1. 大量使用2.0的翻转方法很容易死机(最好用诺基亚自带的翻转方法) 2. drawRegion在这个机型上会拖慢速度,建议使用Nokia UI API上的drawImage 3. 绘图函数调用不当会当机 4. 用了PNG-24文件格式,用Nokia UI API的drawImage画翻转,结果在7610手机上慢的可怜,而且图像还有撕裂现象 |
|
N7260 |
128x128 |
1. Nokia 6230手机:RecordStore类方法openRecordStore(...),第一个参数“String recordStoreName”,字符串不能以“/”开头,否则会找不到也无法创建数据纪录,返回 RecordStoreNotFoundException。 2. 使用platformRequest()方法调用本机浏览器,需要退出程序后才会调用 |
|
Motorola |
C650 |
128x128 |
1. 开启摄像头、内部文件访问权限等需要授权 2. setMediaTime该机型不支持,playerUpdate传过来的player是副本,应该用equal而不是== 3. 必须在jad 文件Midlet-Icon属性中指定图标文件,Midlet-1中指定的图标无效 |
E398 |
176x204 |
1. 左右软键有可能在这个方法中捕获不到。而是否能够成功捕获,取决于keyPressed()方法中代码的行数 2. Triplets内存管理很差,碎片太多,每次过关时释放所有动画图片,争取到一块大的连续内存,然后进入下一关时将需要的动画图片连续载入 3. 手机在播放声音的时候,管理很糟糕,每次在声音刚要播又没播出来的时候,按红键,然后resume,手机几乎会100%Freeze,目前没有解决方法,motorola公司也已经基本承认这个问题是手机自身的问题了 4. 在播放一长段声音的时候,来电话再返回,手机将无法播放mp3,只有手机重起以后才能恢复,也已经和Motorola公司联系过,他们的解释是播放 Midi的时候不会出现这个问题,播放Wave的时候会出现,但是在我们这里的试验是播放两种声音的时候都会有同样的问题 5. hideNotify() 的调用时机时对时错,会导致手机计时错误。当在游戏中按下红键时,hideNotify() 应当立刻被系统调用,但是在联机测试中发现,60% 的时候它是在此时调用的,另外 40% 是在选择了系统的“Resume”后才调用的,如果游戏中需要计时,那么,从按下红键到恢复到游戏中的这段时间就会被计算在游戏时间内,这是不对的 6. MOTO手机的按键处理反应速度特别快,如果使用keyPressed方法,并且切换到拥有Command的高级界面时会出现问题 7. 在从Form到Canvas的屏幕转换时不同的手机的处理方式并不相同,需要引起注意,避免出现处理方式不同而效果不一样的情况。Nokia、NEC、 SE的手机从Form切换到Canvas时会自动进行清屏的操作。而Samsung和MOTO的部分机器则不会,会造成Form的图像还保留屏幕上的情况。解决方法是,最好在切换回Canvas时程序自行进行清屏的操作。 8. MOTO手机字体只有一种,无论设置哪种参数只能取到一种 9. 支持MIDP 2.0,因此可支持全屏幕模式。但是顶部的MOTO手机的电池电量以及网络等图标不会消除。取得全屏的高度时会减去下方的软键区域,而实际上软键区域是可以画图的。 10. copyArea是Graphics的作整块屏幕像素copy的常用API(2D动态背景的游戏几乎是必不可少)。按照Sun官方的Spec,手机厂商有义务来保证其API实现不存在覆盖冲突问题。但是Motorola显然做得不够好。在 Motorola手机上使用这个API会随机产生贴图混乱的情况,解决办法是自己实现另外一套机制。比如使用另外一张至少和屏幕同样大小的Image作为缓冲,用两次drawImage来替代copyArea……不过这个方法显而易见的缺点是消耗了更多的内存(那可是不小于屏幕尺寸的Image啊!)。如果内存实在吃紧,只能退而再求其次,作为缓冲的Image继续缩水,drawImage的次数继续增加……不过这个时候需要自己手工解决覆盖冲突 11. MIDP2.0 Canvas可以调用setFullScreenMode(true)将Canvas设置成全屏,但设置成全屏后新的Canvas width & height的获得对于不同手机却并不一样 12. 调用setFullScreenMode(true)后,将触发sizeChanged事件,此事件从系统接受两个参数,即为Canvas全屏后的width & height,通过这个事件可以获得新的宽高,但要注意,此事件并不是同步的,就是说如果你调用了setFullScreenMode(true)之后,立即使用新的width,height,有可能获得错误的结果 |
|
Sony-Ericsson |
K700C |
176x220 |
1. 支持NOKIA UI API,但是drawpixels()、getpixels()这2个表现差劲不能使用 2. 单个类文件不能超过70K(JAR包压缩后的大小),否则无法加载 3. 左右软键有可能在这个方法中捕获不到。而是否能够成功捕获,取决于keyPressed()方法中代码的行数 4. 左右软件的键值是-6、-7,但对这两个值调用getGameAction会抛Exception,将keypressed中记录方向键的代码放在最后,从而保证左右软件都会被记录下来 5. K700上System.gc()非常耗时,移植到SEK700上时要小心 6. 使用S60的画图函数处理x翻转时出现花屏,使用S60的画图需要手工处理翻转,然后调用不带翻转参数的drawPixels 7. SonyEricsson K700, Z1010, V800, S700这几款手机的堆内存都是512K,但是这些手机的image对象都不是创建在堆内存上,而是创建在“显存”里的,所以,如果直接用 CreateImage和drawImage,将会感觉“内存无限大(1900K)”,不会有内存问题。但是,如果用drawPixels(这些手机内置了Nokia的API)而把所有的象素信息保存在short数组里,就有可能产生内存不足的问题,如果不需要动态更换调色板,尽量使用 CreateImage和DrawImage 8. 运行过程中会有花屏现象,这是因为Nokia60不支持image buffer上的setClip,所以我们都是把tile画到一个tile大小的buffer上,然后再画到背景buffer上。这个解决办法引起了花屏(在其他几款SonyEricson的高端手机上没有发现这个问题),直接在背景buffer上setClip 9. 如果先画一张Image,然后在同一帧将该Image设为null,除此之外,该帧没有对屏幕做任何绘画,则该帧的屏幕将显示这张Image。但是,在下一帧,屏幕将不再显示这张Image,而是显示画Image之前的屏幕内容。常见于画Splash时。在画Image和设为null之后,只要随便往屏幕上画点东西,哪怕是一个象素,屏幕就会持续显示该Image,直到程序画新的内容 10. MIDlet-Version版本号每项不能超过两位数,比如1.0.99正确,1.0.100错误 11. drawRGB方法将忽略变换后的坐标,而始终从手机屏幕的0,0坐标开始 12. 在keyPressed()中调用repaint()进行屏幕重画没有任何反映 13. 调用setFullScreenMode(true)后,不会触发sizeChanged,而是通过getWidth和getHeight获得新的宽高。 SE的setFullScreenMode调用后是立即返回的,所以可以获得正确的width & height 14. 当获得了某个byte[],并希望用UTF8作为字符集将其转换为字符串的时候,使用上述方法在 SonyEricssonK700c上会出现丢失字符的现象 |
S700 |
240x320 |
1. 左右软键会不灵,搞了半天才发现原来S700的getGameAction()不能转换左右软键的-6,-7键值 |
|
Samsung |
D508 |
176x220 |
1. 需要在paint()方法中调用setFullScreenMode(),否则全屏会失效 2. Samsung手机日期问题:其它手机上去的月份是从0月开始的,因此应自行加1,而三星手机是取得实际月份的值 3. 全屏状态下按键响应有Bug,左右软键只能响应keyPressed而不会调用keyReleased,因此会产生很大问题,手工在每个游戏循环中调用keyReleased(-6);keyReleased(-7); 4. g.fillTriangle()方法有BUG,屏幕下方大概三分之一的区域将不会对此API的操作有响应,自己实现fillTriangle的功能 |
开发的时候平台是Nokia 40,然后移植到Nokia 60, Moto V, SE等,总结一下大概需要几个版本:
1. Nokia 40版, 使用Midp1.0+Nokia UI API
2. Nokia 60版, 使用Midp1.0+NOkia UI API
3. Nokia Midp2.0版,如6600,7610,使用Midp2.0
4. Moto V版,使用Midp2.0
5. SE版,使用Midp2.0
6. 三星s100,s200,c100,使用Midp2.0
几点开发经验:
1. 各机型之间最大的差别就是屏幕大小不同。所以游戏中要能自适应屏幕大小
2. 不使用Midp2.0的GameAPI会比较方便移植,只要自己封装切图,旋转等函数即可。NokiaUI API和Midp2。0都支持图片选转。2.0支持的更好。注意Nokia 60不支持创建可变的透明图片,所以要用其他方法代替
3. NOkia 6600,7610的UI API有问题(图片旋转),所以用了Midp2.0代替
4. 支持MIDP2。0的机器程序大致相同,其中MOto,SE,SX都差不多。但也有细微差别。如SE不支持全屏。所以screenSizeChanged方法无效
5. 说说声音播放。NOkia s40上我坚决不用声音,一是容量限制,二是太难听。其他机型都可以支持midi和wav.不过没有发现可以同时播放2个midi的机型,moto v和se都可以同时播放midi和wav,nokia则不行