本文版权归原作者,中国JAVA手机网收录本文的目的是让更多人阅读到此文章。转载请注明出处为中国JAVA手机网<www.cnjm.net>
[本文章最后由 rocks 在2006-02-19 20:21:28编辑过]
来自:http://www.cnjm.net/tech/article866.html [出自: http://expert.imobile.com.cn]
JAVA手机网[www.cnjm.net] 摘要
本系列面向那些习惯使用J2ME的手机开发者,或者那些对更轻便和更有效的代码生成感兴趣的BREW开发者。主要是受Java GUI模型的启发,当前的BREW_J2ME 框架可以处理J2ME中当作“高级别接口”的东西。关于如何提供确切的J2ME匹配-推理不在本文讨论范围之内,本文只是提供这两个领域的概述。
首先我将快速讨论BREW和J2ME之间的差别以及我们如何缩小这个差距,为此我将深入分析设计过程。然后我会给出一个完全的框架。
JAVA手机网[www.cnjm.net] 概述
JAVA手机网[www.cnjm.net] 从一开始,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手机网[www.cnjm.net] 设计
我们的目的就是简化“高级别接口”的代码以及相关的逻辑,使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'配对。
JAVA手机网[www.cnjm.net] 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;
JAVA手机网[www.cnjm.net] virtual int getID() const = 0;
JAVA手机网[www.cnjm.net] virtual IControl* getControl() const = 0; virtual ~IDisplayable() {} };
JAVA手机网[www.cnjm.net] 在BREW中, IDisplayable等于IControl ,即使它展示附助功能。
为了方便,每个应用都从IMidlet抽象类继承而来,这个类负责声明和实现哑元应用级的事件回调(这个稍候再讨论),以及提供对DisplayableRegistry唯一范例的访问。这就解决了另外一个问题——Singleton的实现。请注意:IMidlet提供的机制和动态多形性并不是必要的,从本质上来说——静态多形性也可以做同样的事。让每个组件都理解应用,相当于为他们提供了上下文。
CODE:class IMidlet
JAVA手机网[www.cnjm.net] { public: DisplayableRegistry* getDisplayable() const
JAVA手机网[www.cnjm.net] { return rr_; } void setRegistry(DisplayableRegistry* rr) { rr_ = rr; } virtual bool onStart()
JAVA手机网[www.cnjm.net] {
JAVA手机网[www.cnjm.net] return true; } virtual bool onStop() { return true;
JAVA手机网[www.cnjm.net] } virtual bool onSuspend()
JAVA手机网[www.cnjm.net] {
JAVA手机网[www.cnjm.net] return false; } virtual bool onResume() { return false; } virtual ~IMidlet() {} private: DisplayableRegistry* rr_;
JAVA手机网[www.cnjm.net] };
JAVA手机网[www.cnjm.net] 这里是DisplayableRegistry的一个可能实现:
CODE:class DisplayableRegistry { public: int registerResource(IDisplayable* resource) { for(int i = resources_.size() - 1; i >= 0; --i)
JAVA手机网[www.cnjm.net] { if (resources_[i] && resources_[i] == resource)
JAVA手机网[www.cnjm.net] { return i; }
JAVA手机网[www.cnjm.net] } resources_.append(resource); return resources_.size() - 1; }
bool unregisterResource(int uid) { if (resources_[uid] ) { delete resources_[uid]; resources_[uid] = 0; return true; }
JAVA手机网[www.cnjm.net] return false; } IDisplayable* getRegistered(int uid) const { return resources_.isEmpty() || ((resources_.size()-1) < uid) ? 0 : resources_[uid] ; } void setCurrent(IDisplayable* resource ) { setCurrentImpl(resource); }
JAVA手机网[www.cnjm.net] int getNextAvailableID()
JAVA手机网[www.cnjm.net] { ++itemID_; return itemID_; } bool onCmd(int itemID, long data) const { int id = INDEX_OUT_OF_BOUNDS; for(int i = 0, sz = resources_.size(); i< sz; ++i) { if (resources_[i]->containsItem(itemID)) { IDisplayable* d = resources_[i]; return resources_[i]->onCmd(); }
JAVA手机网[www.cnjm.net] } return false;
Midlet* getApp() const {
JAVA手机网[www.cnjm.net] return m_; } bool isHandled(AEEEvent eCode, uint16 wParam,
JAVA手机网[www.cnjm.net] uint32 dwParam) const { for(int i = 0, sz = resources_.size(); i< sz; ++i) { IControl* c = resources_[i]->getControl(); if (c && ICONTROL_HandleEvent(c,eCode, wParam, dwParam)) return true; } return(false); } ~DisplayableRegistry() {
JAVA手机网[www.cnjm.net] delete m_; unregisterResources(); } DisplayableRegistry(IMidlet* m):itemID_(100), m_(m) { m_->setRegistry(this); } private: void unregisterResources() { for(int i=0, sz = resources_.size(); i < sz; ++i) { delete resources_[i]; resources_[i] = 0; } }
void eraseAll() const { for(int i=0, sz = resources_.size(); i < sz; ++i) { IControl* c = resources_[i]->getControl(); ICONTROL_SetActive(c,false); } IDISPLAY_ClearScreen(getDisplay()); }
void setCurrentImpl(IDisplayable* resource) { eraseAll(); ICONTROL_SetActive(resource->getControl(),true);
JAVA手机网[www.cnjm.net] IDISPLAY_UpdateEx(getDisplay(), false); } private: int itemID_; IMidlet* m_; private: DisplayableRegistry( const DisplayableRegistry &value ); const DisplayableRegistry &operator = ( const DisplayableRegistry &rhs ); };
最后,使登记过程和基于GUID的BREW初始化过程透明化需要一个附助构造——一个工厂。代码的第一行可以这样写:
JAVA手机网[www.cnjm.net] CODE:List* l = List::getList("Title", this);
【未完待续】
JAVA手机网[www.cnjm.net] 源代码下载: cppapp.zip
原文地址:http://www.developer.com/ws/j2me/article.php/3116331
参考文献
1.BREW and J2METM—A Complete Wireless Solution for Operators Committed to Java—Qualcomm http://www.qualcomm.com/brew/images/about/pdf/brew_j2me.pdf
JAVA手机网[www.cnjm.net] 2.Design Patterns: Elements of Reusable Object-Oriented Software—ErichGamma, RichardHelm, RalphJohnson, and John Vlissides, Addison-Wesley, 1994
3.String in BREW Revisited—a BrewString Generalization—http://www.developer.com/ws/brew/article.php/2229051
4.Emulating C++ Exception Handling—Gregory Colvin, C/C++ Users Journal, December 1994
5.For Brew Developers, There Are New Kids in Town: IThread & IRscPool, Part 2—http://www.developer.com/ws/brew/article.php/3105131
关于作者
Radu Braniste 是Epicad的技术主任。联系他请发邮件到: rbraniste@epicad.com 【论坛浏览】 【我来说两句】 【打印】 【大】 【中】 【小】 【关闭】
相关评论 作者: leon 发布日期: 2005-9-29
JAVA手机网[www.cnjm.net] 什么是List?
BREW不提供List,而是提供MenuCtl。简单的说,“List就是一个暴露MenuCtl功能的IDisplayable。”
CODE:template <class T, class P=ListStrategy, class E = ErrorHandler> class ListImpl : public IDisplayable { typedef bool (T::*FNC)(ListImpl<T,P,E>*);
JAVA手机网[www.cnjm.net] public: static ListImpl* getList( const WString& title, T* t) { ListImpl* l = createList(t); if (l) { l->setTitle(title); l->setFullScreen(); } return l; }
virtual ~ListImpl() { if (list_) IMENUCTL_Release(list_); }
void append(const WString& item) { if (!rr_) return; int id = rr_->getNextAvailableID(); IMENUCTL_AddItem(list_, 0, 0, id, const_cast<AECHAR*>
JAVA手机网[www.cnjm.net] (item.toCharArray()), 0); indxs_.append(id); }
JAVA手机网[www.cnjm.net]
JAVA手机网[www.cnjm.net] void append(const WString items[]s, int sz) { for(int i=0; i < sz; ++i) { append(items[i]); } }
JAVA手机网[www.cnjm.net] virtual IControl* getControl() const { return reinterpret_cast<IControl*>(list_); }
bool onCmd() { if (fnc_ && t_) return (*t_.*fnc_)(this); return false;
JAVA手机网[www.cnjm.net] }
int getSelectedIndex() const { return selected_;
JAVA手机网[www.cnjm.net] }
virtual bool containsItem(int ix) { selected_ = getIDImpl(ix); return (selected_ != INDEX_OUT_OF_BOUNDS); }
virtual int getID() const { return id_; }
void setCbk(FNC f) { fnc_ = f; }
void setSelection(int id) { int lid = IMENUCTL_GetItemID(list_, id); IMENUCTL_SetSel(list_, lid); }
int size() const { return indxs_.size(); }
JAVA手机网[www.cnjm.net] void setTitle(const WString& title) { if (title.length()) IMENUCTL_SetTitle(list_, NULL, 0, const_cast<AECHAR*> (title.toCharArray())); }
private:
ListImpl( T* t, AEECLSID cid ): list_(0), t_(t) , rr_(0), shell_(getShell()), selected_(0) { if (shell_) ISHELL_CreateInstance(shell_, cid, (void **)&list_); if (!list_) { E::onMemAllocError(WString(__FILE__), WString((long)__LINE__)); return; }
rr_ = t_->getDisplayable(); if (rr_)
JAVA手机网[www.cnjm.net] id_ = rr_->registerResource(this); }
static ListImpl* createList( T* t, AEECLSID cid = AEECLSID_MENUCTL) { ListImpl* l = new ListImpl( t, cid); if (!l->list_) { delete l; return 0; } return l; }
void setFullScreen();
int getIDImpl(int ix);
JAVA手机网[www.cnjm.net] private: IMenuCtl * list_; FNC fnc_; T* t_;
JAVA手机网[www.cnjm.net] DisplayableRegistry* rr_;
JAVA手机网[www.cnjm.net] int selected_; int id_; IShell * shell_; BrewVector<int> indxs_; };
JAVA手机网[www.cnjm.net] 下一个概念就是事件处理。显然,BREW 和Java之间存在的重要差别包括:一个唯一的ID、事件循环机制配对一个固有的,基于监视器的机制。我说“显然”,那是因为机制之间可以自由切换。甚至J2ME可以共享BREW的缺陷——命令听取者的实现与BREW事件循环紧密关联——这个缺陷通常是一个难于维护的、巨大的“转换”。在此之上,听取者是一个类型很差的构造,它暴露一个不得不被用户抛弃的Displayable接口。我们的框架提供一个更安全的方法,它拥有类型安全的、J2SE风格的听取者。例如, ListImpl 类可定义一个听取者:
CODE:typedef bool (T::*FNC)(ListImpl<T,P,E>*);
实现如下:
JAVA手机网[www.cnjm.net] CODE:bool myListUsage( List* l)
JAVA手机网[www.cnjm.net] {
JAVA手机网[www.cnjm.net] int pos = l->getSelectedIndex();
JAVA手机网[www.cnjm.net] return (pos == INDEX_OUT_OF_BOUNDS) ? false : BuildCommand(pos), true; }
并且登记如下:
CODE:l->setCommandListener(myListUsage);
Java有一个更好的getSelected() 机制来取代传送到IMENUCTL_AddItem 的唯一标志。通过使用普遍存在的DisplayableRegistry,我们可以很容易的实现它,这段时间内产生的唯一标志在内部可作为ID使用。请注意在某些特殊的情况下使用政策可加快ID的检索。
JAVA手机网[www.cnjm.net] BREW 和Java之间的一个明显差别在于故障处理,基于RTTI的异常处理在BREW中不可用或者使用成本过高。使用setjmp/longjmp 模拟try/catch机制由于销毁自动对象有问题不能直接应用,但是其他的技能是可用的。为了方便,我们将ErrorHandler当作政策——适当提供异常追踪信息的一种方式——来提供。
包装
让我们使用上述技巧从头开始写一个应用程序。
框架封装在cppapp和brewJ2ME内。一个应用就是一个类——与文件MyApp.h 中的Midlet差不多。以下是编写应用的步骤:
JAVA手机网[www.cnjm.net] 1.将 "MyApp.h"包括在cppapp.h之内。
2.创建一个继承于IMidlet 的Midlet 类。
3.将APPLICATION_TYPE 的类型定义为 Midlet。
结果产生的框架为:
JAVA手机网[www.cnjm.net] CODE:class Midlet : public IMidlet { }; typedef Midlet APPLICATION_TYPE ;
我们的简单应用将处理两个清单,每一个都包含四项——{"1","2","3","4"} 和{"A","B","C","D"}。例如,按下"1,",我们将看到相应的"A," ,按下 "C" 就转换为"3,",以此类推。这种逻辑可嵌入到两个事件处理器内:my14ListUsage和myADListUsage。
CODE:class Midlet : public IMidlet { typedef ListImpl<Midlet> List; private: bool my14ListUsage( List* l) { int pos = l->getSelectedIndex(); return (pos == INDEX_OUT_OF_BOUNDS) ? false : BuildADList(pos), true; } bool myADListUsage( List* l) { int pos = l->getSelectedIndex(); return (pos == INDEX_OUT_OF_BOUNDS) ? false : Build14List(pos), true; } List * Init14List() { List* l = List::getList("List14", this);
JAVA手机网[www.cnjm.net] if (!l) return 0; l->setCbk(my14ListUsage); WString a[] = {"1","2","3","4"}; l->append(a,SIZE_OF(a)); return l; } List * InitADList() {
JAVA手机网[www.cnjm.net] List* l = List::getList("ListAD", this);
JAVA手机网[www.cnjm.net] if (!l) return 0; l->setCbk(myADListUsage); WString a[] = {"A","B","C","D"}; l->append(a,SIZE_OF(a)); return l; } void BuildADList(int ix ) { if (!lAD_) { lAD_ =InitADList(); } BuildList(lAD_, ix); } void Build14List(int ix ) { if (!l14_)
JAVA手机网[www.cnjm.net] { l14_ = Init14List(); }
JAVA手机网[www.cnjm.net] BuildList(l14_, ix); }
JAVA手机网[www.cnjm.net] void BuildList(List* l , int ix) { if (!l || (l->size()-1)<ix) return; l->setSelection(ix); getDisplayable()->setCurrent(l); } public: virtual bool onStart() { l14_ = 0; lAD_ = 0; BuildADList(2); return true; } private: List* l14_; List* lAD_; };
我们真正感兴趣的不是代码的明显简化,而是事件处理的透明性。
前景
JAVA手机网[www.cnjm.net] 这个最初的尝试并没有包括重要内容如多-控制屏幕、处理事件而不是处理EVT_COMMAND、以及控制登记过的资源。下一个部分将讨论所有这些内容以及扩展该框架的机制。
【完】
源代码下载: cppapp.zip
JAVA手机网[www.cnjm.net] 原文地址:http://www.developer.com/ws/j2me/article.php/3116331
参考文献
1.BREW and J2METM—A Complete Wireless Solution for Operators Committed to Java—Qualcomm http://www.qualcomm.com/brew/images/about/pdf/brew_j2me.pdf
JAVA手机网[www.cnjm.net] 2.Design Patterns: Elements of Reusable Object-Oriented Software—ErichGamma, RichardHelm, RalphJohnson, and John Vlissides, Addison-Wesley, 1994
3.String in BREW Revisited—a BrewString Generalization— http://www.developer.com/ws/brew/article.php/2229051
4.Emulating C++ Exception Handling—Gregory Colvin, C/C++ Users Journal, December 1994
5.For Brew Developers, There Are New Kids in Town: IThread & IRscPool, Part 2— http://www.developer.com/ws/brew/article.php/3105131
关于作者
JAVA手机网[www.cnjm.net] Radu Braniste 是Epicad的技术主任。联系他请发邮件到: rbraniste@epicad.com
来自:http://www.cnjm.net/tech/article866.html
|