用户: 密码: 答案:   我要注册   忘记密码

加入收藏  设为首页

开发文档

CNJM首页

业界新闻

手机软件

终端应用

资源下载

EclipseME

CNJM论坛

                 

频道列表

J2ME开发 176篇
服务器端开发 33篇
JAVA语言 71篇
游戏与图形 101篇
WindowsMobile开发 6篇
Symbian开发 61篇
Brew开发 36篇
其它开发平台 6篇

热点文章

BREW™ SDK入门篇...  8246次
BREW开发相关技术论坛 7329次
BREW究竟是什么-B... 7271次
[原创]BREW高手之...  7213次
BREW & J2ME:在差...  7142次
BREW™ SDK入门篇...  6795次
深入Brew编程之一...  6760次
深入BREW消息处理机制 6312次
深入BREW模块加载机制 6185次
BREW SDK入门 6076次
联通博路的开发商F... 5793次
[原创] brew下的大... 5378次

文章搜索

搜 索
按 照
频 道
  
BREW & J2ME:在差别中联合
编辑:rocks    审核:rocks    文章来源:expert.imobile.com.cn
关键词:brew    发表日期:2006-02-17 15:18:20    浏览次数:7142次
本文版权归原作者,中国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

相关文章
    BREW开发相关技术论坛  [2005-10-15]
    联通博路的开发商FTP文件列表  [2004-01-15]
最新评论
网站简介  |  关于版权  |  广告服务  |  网站地图  |  联系我们
Copyright © www.CNJM.net, All rights reserved
中国JAVA手机网 版权所有
ICP备案:京ICP备041452