返回列表 回复 发帖
所需阅读权限 1

[分享]BREW&J2ME:在差别中联合(1)

[这个帖子最后由cnangel在 2004/05/25 05:51pm 第 1 次编辑]

作者:Radu Braniste
目录

摘要
概述
设计
源代码下载
原文地址
参考文献
关于作者

摘要

本系列面向那些习惯使用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开发者的工作更轻松。这就意味着,至少从理论上说,我们能够编写以下代码:
  1. List* l = new List("Title");
  2. l->setCommandListener(myListUsage);
  3. String a[] = {"1","2","3","4"};
  4. l->append(a);
  5. 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 接口:
  1. struct IDisplayable
  2. {
  3.   virtual bool onCmd() = 0;
  4.   virtual bool containsItem(int idx) = 0;
  5.   virtual int getID() const = 0;
  6.   virtual IControl* getControl() const = 0;
  7.   virtual ~IDisplayable()
  8.   {}
  9. };
复制代码
在BREW中, IDisplayable等于IControl ,即使它展示附助功能。

为了方便,每个应用都从IMidlet抽象类继承而来,这个类负责声明和实现哑元应用级的事件回调(这个稍候再讨论),以及提供对DisplayableRegistry唯一范例的访问。这就解决了另外一个问题——Singleton的实现。请注意:IMidlet提供的机制和动态多形性并不是必要的,从本质上来说——静态多形性也可以做同样的事。让每个组件都理解应用,相当于为他们提供了上下文。
  1. class IMidlet
  2. {
  3. public:
  4.   DisplayableRegistry* getDisplayable() const
  5.   {
  6.     return rr_;
  7.   }
  8.   void setRegistry(DisplayableRegistry* rr)
  9.   {
  10.     rr_ = rr;
  11.   }
  12.   virtual bool onStart()
  13.   {
  14.     return true;
  15.   }
  16.   virtual bool onStop()
  17.   {
  18.     return true;
  19.   }
  20.   virtual bool onSuspend()
  21.   {
  22.     return false;
  23.   }
  24.   virtual bool onResume()
  25.   {
  26.     return false;
  27.   }
  28.   virtual ~IMidlet()
  29.   {}
  30. private:
  31.   DisplayableRegistry* rr_;
  32. };
复制代码
这里是DisplayableRegistry的一个可能实现:
  1. class DisplayableRegistry
  2. {
  3. public:
  4.   int registerResource(IDisplayable* resource)
  5.   {
  6.     for(int i = resources_.size() - 1; i >= 0; --i)
  7.     {
  8.       if (resources_[i] && resources_[i] == resource)
  9.       {
  10.         return i;
  11.       }
  12.     }
  13.     resources_.append(resource);
  14.     return resources_.size() - 1;
  15.   }
  16.   bool unregisterResource(int uid)
  17.   {
  18.     if (resources_[uid] )
  19.     {
  20.       delete resources_[uid];
  21.       resources_[uid] = 0;
  22.       return true;
  23.     }
  24.     return false;
  25.   }
  26.   IDisplayable* getRegistered(int uid) const
  27.   {
  28.     return resources_.isEmpty() || ((resources_.size()-1) < uid)
  29.                                    ? 0 : resources_[uid] ;
  30.   }
  31.   void setCurrent(IDisplayable* resource )
  32.   {
  33.     setCurrentImpl(resource);
  34.   }
  35.   int getNextAvailableID()
  36.   {
  37.     ++itemID_;
  38.     return itemID_;
  39.   }
  40.   bool onCmd(int itemID, long data) const
  41.   {
  42.     int id = INDEX_OUT_OF_BOUNDS;
  43.     for(int i = 0, sz = resources_.size(); i< sz; ++i)
  44.     {
  45.       if (resources_[i]->containsItem(itemID))
  46.       {
  47.         IDisplayable* d = resources_[i];
  48.         return resources_[i]->onCmd();
  49.       }
  50.     }
  51.     return false;
  52.    
  53.     Midlet* getApp() const
  54.   {
  55.     return m_;
  56.   }
  57.   bool isHandled(AEEEvent eCode, uint16 wParam,
  58.                  uint32 dwParam) const
  59.   {
  60.     for(int i = 0, sz = resources_.size(); i< sz; ++i)
  61.     {
  62.       IControl* c = resources_[i]->getControl();
  63.       if (c && ICONTROL_HandleEvent(c,eCode, wParam, dwParam))
  64.         return true;
  65.     }
  66.     return(false);
  67.   }
  68.   ~DisplayableRegistry()
  69.   {
  70.     delete m_;
  71.     unregisterResources();
  72.   }
  73.   DisplayableRegistry(IMidlet* m):itemID_(100), m_(m)
  74.   {
  75.     m_->setRegistry(this);
  76.   }
  77. private:
  78.   void unregisterResources()
  79.   {
  80.     for(int i=0, sz = resources_.size(); i < sz; ++i)
  81.     {
  82.       delete resources_[i];
  83.       resources_[i] = 0;
  84.     }
  85.   }
  86.   void eraseAll() const
  87.   {
  88.     for(int i=0, sz = resources_.size(); i < sz; ++i)
  89.     {
  90.       IControl* c = resources_[i]->getControl();
  91.       ICONTROL_SetActive(c,false);
  92.     }
  93.     IDISPLAY_ClearScreen(getDisplay());
  94.   }
  95.   void setCurrentImpl(IDisplayable* resource)
  96.   {
  97.     eraseAll();
  98.     ICONTROL_SetActive(resource->getControl(),true);
  99.     IDISPLAY_UpdateEx(getDisplay(), false);
  100.   }
  101. private:
  102.   int itemID_;
  103.   IMidlet* m_;
  104. private:
  105.   DisplayableRegistry( const DisplayableRegistry &value );
  106.   const DisplayableRegistry &operator =
  107.         ( const DisplayableRegistry &rhs );
  108. };
复制代码
最后,使登记过程和基于GUID的BREW初始化过程透明化需要一个附助构造——一个工厂。代码的第一行可以这样写:
  1. List* l = List::getList("Title", this);
复制代码

                     我是一个呼吸着现在的空气而生活在过去的人
               这样的注定孤独,孤独的身处闹市却犹如置身于荒漠
                                     我已习惯了孤独,爱上孤独
                                 他让我看清了自我,还原了自我
                             让我再静静的沉思中得到快乐和满足
                                   再孤独的世界里我一遍又一遍
                                   不厌其烦的改写着自己的过去
                                             延伸到现在与未来
                                       然而那只是泡沫般的美梦
                                 产生的时刻又伴随着破灭的到来
                         在灰飞烟灭的瞬间我看到的是过程的美丽
                                      而不是结果的悲哀。。。
返回列表