摘要
本系列面向那些习惯使用J2ME的手机开发者,或者那些对更轻便和更有效的代码生成感兴趣的BREW开发者。主要是受Java GUI模型的启发,当前的BREW_J2ME 框架可以处理J2ME中当作“高级别接口”的东西。关于如何提供确切的J2ME匹配-推理不在本文讨论范围之内,本文只是提供这两个领域的概述。
首先我将快速讨论BREW和J2ME之间的差别以及我们如何缩小这个差距,为此我将深入分析设计过程。然后我会给出一个完全的框架。
概述
从一开始,Qualcomm试图将BREW定位为中立语言,将C/C++定位为最好的语言选择——其它语言总能为应用开发所用就行。从技术的观点来看,这个理论看似相当合理——新的语言总是能够作为静态扩展来实现,还包括了原来的BREW功能。作为一个附带的优点,成为扩展可以立即得到BREW分布式系统(BDS)的所有优点。这是好的方面。但是,他有什么负面影响呢?
这种实现原本就比直接在OS上实现更慢,更笨重(因为所有OS调用都经BREW中转)。现在,J2ME:BREW比标准的MIDP(甚至是2.0版本)提供的功能要多得多,也就是说可能会出现一个非标准的API来填补它们之间差距。
当然,编程语言的选择主要是一个商业决定,与比较他们的优点无关。J2ME:BREW最吸引人的地方就是为Java开发者使用C++语言编写BREW应用提供一个更熟悉的方式。从开发者的观点来看,这明显意味着要熟悉J2ME和BREW之间的界限和差别。
他们之间的差别有的源于Java vs C++的争论——例如,存储处理、多重继承、类型安全、泛型等等。有的源于BREW的局限性——典型的如缺乏静态变量的支持、缺乏C++的支持级别、缺乏多任务合作、开发者兼管监察活动等等。当然,Java在BREW之上就意味着Java得接受所有这些差别。还有的源于基础设计决定,如时间模型、组件等等。当然,如前所述,J2ME是一组平台独立的规范,他没有为某些BREW功能提供相应的配对物。
设计
我们的目的就是简化“高级别接口”的代码以及相关的逻辑,使Java开发者的工作更轻松。这就意味着,至少从理论上说,我们能够编写以下代码:
CODE:List* l = new List("Title");
l->setCommandListener(myListUsage);
String a[] = {"1","2","3","4"};
l->append(a);
Display.getDisplayable()->setCurrent(l);:
正如概述中看到的一样,有不同的因素影响着设计,如(不分顺序): 没有内建的垃圾收集器;就某种意义上来说没有静态变量=没有Singleton;没有根对象但有安全类型泛型,等等。考虑到所有这些因素,我们就会了解为什么上述代码不能够在BREW中自由编写。其可能原因有:
1.没有List。
2.'new' 必须与'delete'配对。
3.没有可用的字符串或者广义的字符串。
4.将AECHARs 直接置于堆栈是危险的。
5.没有听取者。
6.Singleton难于实现。
BREW_J2ME框架的任务就是为解决这种问题提供最好的可能方案。
BREW_J2ME框架最重要的决定之一是关于存储管理和对象周期的。如果没有删除,谁负责销毁我们的小器件呢?明显的答案如基于堆栈的对象和职能指针,职能指针可用于限制范围的生命周期或者引用计算(这与BREW方案保持一致)。以前文章中用过的一个方案就是:登记对象并将对象周期与登记处周期捆绑在一起。这就意味着要添加一个层(登记处)并且能够追踪某个地方所有资源。直接在BREW上创建的C++应用不是第一级别的C++对象,而只是一个POD结构。那就是为什么真正的C++操作明确需要这样一个绝缘层的原因。我们接下来将调用我们的登记处DisplayableRegistry。
我们的登记处主要追踪可显示的资源,实现IDisplayable 接口:
CODE:struct IDisplayable
{
virtual bool onCmd() = 0;
virtual bool containsItem(int idx) = 0;
virtual int getID() const = 0;
virtual IControl* getControl() const = 0;
virtual ~IDisplayable()
{}
};
在BREW中, IDisplayable等于IControl ,即使它展示附助功能。