没学过javaspring 怎么学xmppconnection

Android 基于XMPP Smack Openfire 搜寻服务器的联系人_Ehcache学习(三)_MIDlet API 2.0学习之:javax.microedition.lcdui (1)__脚本百事通
稍等,加载中……
^_^请注意,有可能下面的2篇文章才是您想要的内容:
Android 基于XMPP Smack Openfire 搜寻服务器的联系人
Ehcache学习(三)
MIDlet API 2.0学习之:javax.microedition.lcdui (1)
Android 基于XMPP Smack Openfire 搜寻服务器的联系人
Android 基于XMPP Smack Openfire 搜索服务器的联系人
Android Smack UserSearchManager (java.lang.ClassCastException java.lang.NullPointerException)用smack 开发IM 聊天工具时, 会用到UserSearchManager 来搜索服务器的联系人
判断用户是否存在等等,代码如下:
UserSearchManager search = new UserSearchManager(ClientConnectionServer.connection);
Form searchForm =
searchForm = search.getSearchForm("search." + ClientConnectionServer.connection.getServiceName());
catch (XMPPException e1)
e1.printStackTrace();
Form answerForm = searchForm.createAnswerForm();
answerForm.setAnswer("Username", true);
answerForm.setAnswer("search", editContact.getText().toString());
ReportedData data =
data = search.getSearchResults(answerForm, "search." + ClientConnectionServer.connection.getServiceName());
catch (XMPPException e1)
e1.printStackTrace();
String result = "";
if (null != data && data.getRows() != null)
Iterator&Row& it = data.getRows();
while (it.hasNext())
row = it.next();
String name = row.getValues("Username").next().toString();
此时红色部分会报 java.lang.NullPointerException, 一种解决办法是在红色代码前加:ProviderManager.getInstance().addIQProvider("query", "jabber:iq:search", new UserSearch.Provider());
但下面还会报 java.lang.ClassCastException , 国外论坛有人解答时jar 包 引用问题,解决办法是在XMPPConnection初始化前,加个configure()方法完成一些设置,可以同时解决上面种异常,代码为:
public void configure(ProviderManager pm)
// Private Data Storage
pm.addIQProvider("query", "jabber:iq:private", new PrivateDataManager.PrivateDataIQProvider());
pm.addIQProvider("query", "jabber:iq:time", Class.forName("org.jivesoftware.smackx.packet.Time"));
catch (ClassNotFoundException e)
Log.w("TestClient", "Can't load class for org.jivesoftware.smackx.packet.Time");
// Roster Exchange
pm.addExtensionProvider("x", "jabber:x:roster", new RosterExchangeProvider());
// Message Events
pm.addExtensionProvider("x", "jabber:x:event", new MessageEventProvider());
// Chat State
pm.addExtensionProvider("active", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
pm.addExtensionProvider("composing", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
pm.addExtensionProvider("paused", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
pm.addExtensionProvider("inactive", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
pm.addExtensionProvider("gone", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
pm.addExtensionProvider("html", "http://jabber.org/protocol/xhtml-im", new XHTMLExtensionProvider());
// Group Chat Invitations
pm.addExtensionProvider("x", "jabber:x:conference", new GroupChatInvitation.Provider());
// Service Discovery # Items
pm.addIQProvider("query", "http://jabber.org/protocol/disco#items", new DiscoverItemsProvider());
// Service Discovery # Info
pm.addIQProvider("query", "http://jabber.org/protocol/disco#info", new DiscoverInfoProvider());
// Data Forms
pm.addExtensionProvider("x", "jabber:x:data", new DataFormProvider());
// MUC User
pm.addExtensionProvider("x", "http://jabber.org/protocol/muc#user", new MUCUserProvider());
// MUC Admin
pm.addIQProvider("query", "http://jabber.org/protocol/muc#admin", new MUCAdminProvider());
// MUC Owner
pm.addIQProvider("query", "http://jabber.org/protocol/muc#owner", new MUCOwnerProvider());
// Delayed Delivery
pm.addExtensionProvider("x", "jabber:x:delay", new DelayInformationProvider());
// Version
pm.addIQProvider("query", "jabber:iq:version", Class.forName("org.jivesoftware.smackx.packet.Version"));
catch (ClassNotFoundException e)
// Not sure what's happening here.
pm.addIQProvider("vCard", "vcard-temp", new VCardProvider());
// Offline Message Requests
pm.addIQProvider("offline", "http://jabber.org/protocol/offline", new OfflineMessageRequest.Provider());
// Offline Message Indicator
pm.addExtensionProvider("offline", "http://jabber.org/protocol/offline", new OfflineMessageInfo.Provider());
// Last Activity
pm.addIQProvider("query", "jabber:iq:last", new LastActivity.Provider());
// User Search
pm.addIQProvider("query", "jabber:iq:search", new UserSearch.Provider());
// SharedGroupsInfo
pm.addIQProvider("sharedgroup", "http://www.jivesoftware.org/protocol/sharedgroup", new SharedGroupsInfo.Provider());
// JEP-33: Extended Stanza Addressing
pm.addExtensionProvider("addresses", "http://jabber.org/protocol/address", new MultipleAddressesProvider());
// FileTransfer
pm.addIQProvider("si", "http://jabber.org/protocol/si", new StreamInitiationProvider());
pm.addIQProvider("query", "http://jabber.org/protocol/bytestreams", new BytestreamsProvider());
// Privacy
pm.addIQProvider("query", "jabber:iq:privacy", new PrivacyProvider());
pm.addIQProvider("command", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider());
pm.addExtensionProvider("malformed-action", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.MalformedActionError());
pm.addExtensionProvider("bad-locale", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.BadLocaleError());
pm.addExtensionProvider("bad-payload", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.BadPayloadError());
pm.addExtensionProvider("bad-sessionid", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.BadSessionIDError());
pm.addExtensionProvider("session-expired", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.SessionExpiredError());
Ehcache学习(三)
Ehcache学习(3)
需要使用 Spring
来实现一个 Cache 简单的解决方案,具体需求如下:使用任意一个现有开源 Cache Framework,要求使用 Cache
系统中 Service 或则 DAO 层的 get/find 等方法返回结果,如果数据更新(使用 Create/update/delete
方法),则刷新 cache 中相应的内容。根据需求,计划使用 Spring AOP + ehCache 来实现这个功能,采用 ehCache
原因之一是Spring 提供了 ehCache 的支持,至于为何仅仅支持 ehCache
而不支持 osCache 和JBossCache 无从得知(Hibernate???),但毕竟 Spring
提供了支持,可以减少一部分工作量:)。二是后来实现了 OSCache 和 JBoss Cache 的方式后,经过简单测试发现几个 Cache
在效率上没有太大的区别(不考虑集群),决定采用 ehCahce。AOP 嘛,少不了拦截器,先创建一个实现了 MethodInterceptor
接口的拦截器,用来拦截Service/DAO 的方法调用,拦截到方法后,搜索该方法的结果在 cache 中是否存在,如果存在,返回
cache 中的缓存结果,如果不存在,返回查询数据库的结果,并将结果缓存到 cache 中。
MethodCacheInterceptor.java
package com.co.cache.
import java.io.S
import net.sf.ehcache.C
import net.sf.ehcache.E
import org.aopalliance.intercept.MethodI
import org.aopalliance.intercept.MethodI
import mons.logging.L
import mons.logging.LogF
import org.springframework.beans.factory.InitializingB
import org.springframework.util.A
public class MethodCacheInterceptor implements MethodInterceptor, InitializingBean
private static final Log logger = LogFactory.getLog(MethodCacheInterceptor.class);
public void setCache(Cache cache) {
this.cache =
public MethodCacheInterceptor() {
Service/DAO
的方法,并查找该结果是否存在,如果存在就返回
否则,返回数据库查询结果,并将查询结果放入
public Object invoke(MethodInvocation invocation) throws Throwable {
String targetName = invocation.getThis().getClass().getName();
String methodName = invocation.getMethod().getName();
Object[] arguments = invocation.getArguments();
logger.debug("Find object from cache is " + cache.getName());
String cacheKey = getCacheKey(targetName, methodName, arguments);
Element element = cache.get(cacheKey);
if (element == null) {
logger.debug("Hold up method , Get method result and create cache........!");
result = invocation.proceed();
element = new Element(cacheKey, (Serializable) result);
cache.put(element);
return element.getValue();
的唯一标识
* cache key
包括 包名
方法名,如
com.co.cache.service.UserServiceImpl.getAllUser
private String getCacheKey(String targetName, String methodName, Object[] arguments) {
StringBuffer sb = new StringBuffer();
sb.append(targetName).append(".").append(methodName);
if ((arguments != null) && (arguments.length != 0)) {
for (int i = 0; i & arguments. i++) {
sb.append(".").append(arguments[i]);
return sb.toString();
* implement InitializingBean
public void afterPropertiesSet() throws Exception {
Assert.notNull(cache, "Need a cache. Please use setCache(Cache) create it.");
上面的代码中可以看到,在方法
public Object invoke(MethodInvocation invocation)
中,完成了搜索
Element element = cache.get(cacheKey);
这句代码的作用是获取
不存在,将会返回一个
result = invocation.proceed();
这句代码的作用是获取所拦截方法的返回值,详细请查阅
相关文档。随后,再建立一个拦截器
MethodCacheAfterAdvice
,作用是在用户进行
create/update/delete
操作时来刷新
内容,这个拦截器实现了
AfterReturningAdvice
接口,将会在所拦截的方法执行后执行在
public void afterReturning(Object arg0, Method arg1,Object[] arg2, Object arg3)
方法中所预定的操作
package com.co.cache.
import java.lang.reflect.M
import java.util.L
import net.sf.ehcache.C
import mons.logging.L
import mons.logging.LogF
import org.springframework.aop.AfterReturningA
import org.springframework.beans.factory.InitializingB
import org.springframework.util.A
public class MethodCacheAfterAdvice implements AfterReturningAdvice, InitializingBean
private static final Log logger = LogFactory.getLog(MethodCacheAfterAdvice.class);
public void setCache(Cache cache) {
this.cache =
public MethodCacheAfterAdvice() {
public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws
Throwable {
String className = arg3.getClass().getName();
List list = cache.getKeys();
for(int i = 0;i&list.size();i++){
String cacheKey = String.valueOf(list.get(i));
if(cacheKey.startsWith(className)){
cache.remove(cacheKey);
logger.debug("remove cache " + cacheKey);
public void afterPropertiesSet() throws Exception {
Assert.notNull(cache, "Need a cache. Please use setCache(Cache) create it.");
上面的代码很简单,实现了
afterReturning
方法实现自
AfterReturningAdvice
接口,方法中所定义的内容将会在目标方法执行后执行,在该方法中的作用是获取目标
的全名,如:
com.co.cache.test.TestServiceImpl
,然后循环
中所有和该
String className = arg3.getClass().getName();
随后,开始配置
文件来设置
相关的一些属性,如最大缓存数量、
刷新的时间等等
ehcache.xml
&diskStore path="c:\\myapp\\cache"/&
&defaultCache
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
&cache name="DEFAULT_CACHE"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="300000"
timeToLiveSeconds="600000"
overflowToDisk="true"
&/ehcache&
配置每一项的详细作用不再详细解释,有兴趣的请
下 ,这里需要注意一点
defaultCache
标签定义了一个默认的
是不能删除的,否则会抛出
No default cache is configured
异常。另外,由于使用拦截器来刷新
内容,因此在定义
生命周期时可以定义较大的数值,
timeToIdleSeconds="300000"
timeToLiveSeconds="600000"
,好像还不够大?然后,在将
和两个拦截器配置到
,这里没有使用
cacheContext.xml
&?xml version="1.0" encoding="UTF-8"?&
&!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd
&bean id="defaultCacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"&
&property name="configLocation"&
&value&ehcache.xml&/value&
&/property&
的工厂,并设置所使用的
Cache name --&
&bean id="ehCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean"&
&property name="cacheManager"&
&ref local="defaultCacheManager"/&
&/property&
&property name="cacheName"&
&value&DEFAULT_CACHE&/value&
&/property&
&!-- find/create cache
&bean id="methodCacheInterceptor"
class="com.co.cache.ehcache.MethodCacheInterceptor"&
&property name="cache"&
&ref local="ehCache" /&
&/property&
&!-- flush cache
&bean id="methodCacheAfterAdvice"
class="com.co.cache.ehcache.MethodCacheAfterAdvice"&
&property name="cache"&
&ref local="ehCache" /&
&/property&
&bean id="methodCachePointCut"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"&
&property name="advice"&
&ref local="methodCacheInterceptor"/&
&/property&
&property name="patterns"&
&value&.*find.*&/value&
&value&.*get.*&/value&
&/property&
&bean id="methodCachePointCutAdvice"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"&
&property name="advice"&
&ref local="methodCacheAfterAdvice"/&
&/property&
&property name="patterns"&
&value&.*create.*&/value&
&value&.*update.*&/value&
&value&.*delete.*&/value&
&/property&
上面的代码最终创建了两个
methodCachePointCut
methodCachePointCutAdvice
,分别用于拦截不同方法名的方法,可以根据需要任意增加所需要拦截方法的名称。需要注意的是
&bean id="ehCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean"&
&property name="cacheManager"&
&ref local="defaultCacheManager"/&
&/property&
&property name="cacheName"&
&value&DEFAULT_CACHE&/value&
&/property&
属性内设置的
ehCache.xml
中无法找到,那么将使用默认的
cache(defaultCache
,事实上到了这里,一个简单的
+ ehCache Framework
基本完成了,为了测试效果,举一个实际应用的例子,定义一个
TestService
和它的实现类
TestServiceImpl
,里面包含两个方法
getAllObject()
updateObject(Object Object)
,具体代码如下:
TestService.java
package com.co.cache.
import java.util.L
public interface TestService {
public List getAllObject();
public void updateObject(Object Object);
TestServiceImpl.java
package com.co.cache.
import java.util.L
public class TestServiceImpl implements TestService
public List getAllObject() {
System.out.println("---TestService
内不存在该
,查找并放入
public void updateObject(Object Object) {
System.out.println("---TestService
:更新了对象,这个
applicationContext.xml
&?xml version="1.0" encoding="UTF-8"?&
&!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd
&import resource="cacheContext.xml"/&
&bean id="testServiceTarget" class="com.co.cache.test.TestServiceImpl"/&
&bean id="testService" class="org.springframework.aop.framework.ProxyFactoryBean"&
&property name="target"&
&ref local="testServiceTarget"/&
&/property&
&property name="interceptorNames"&
&value&methodCachePointCut&/value&
&value&methodCachePointCutAdvice&/value&
&/property&
这里一定不能忘记
import cacheContext.xml
文件,不然定义的两个拦截器就没办法使用
最后,写一个测试的代码
MainTest.java
(DEFAULT_CONTEXT_FILE);
TestService testService = (TestService)context.getBean("testService");
System.out.println("1--
第一次查找并创建
testService.getAllObject();
System.out.println("2--
testService.getAllObject();
System.out.println("3--remove cache");
testService.updateObject(null);
System.out.println("4--
需要重新查找并创建
testService.getAllObject();
运行,结果如下
第一次查找并创建
---TestService
内不存在该
,查找并放入
3--remove cache
---TestService
:更新了对象,这个
需要重新查找并创建
---TestService
内不存在该
,查找并放入
可以看到,第一步执行
getAllObject()
TestServiceImpl
内的方法,并创建了
,在第二次执行
getAllObject()
方法时,由于
有该方法的缓存,直接从
出方法的结果,所以没有打印出
TestServiceImpl
中的内容,而第三步,调用了
updateObject
TestServiceImpl
,所以在第四步执行时,又执行
TestServiceImpl
中的方法,创建
。网上也有不少类似的例子,但是很多都不是很完备,自己参考了一些例子的代码,其实在
spring-modules
中也提供了对几种
JBossCache
这些,看了一下,基本上都是采用类似的方式,只不过封装的更完善一些,主要思路也还是
,有兴趣的可以研究一下。
MIDlet API 2.0学习之:javax.microedition.lcdui (1)
MIDlet API 2.0学习之:javax.microedition.lcdui (一)
j2me实际开发中ui、io包是很重要的。Package javax.microedition.lcdui DescriptionUI API为MIDP应用程序的用户界面实现提供了一套图形User InterfaceMIDP主要标准已经起草,移动信息设备已被考虑在内(也就是移动电话和寻呼机)。这些设备在很多方面和桌面系统不同,特别是UI部分。当设计UI API时,下面UI相关的需求是很重要的:*
设备和应用应该对那些并不熟练使用电脑的人来说是有用的。*
设备和应用应该在用户不能全身心关注应用的情况下是有用的。例如:多个手机型设备可以通过一只手来操作。*
设备之间的表格元素和UI概念都有区别,特别是和桌面系统。例如,显示区域大小更小,输入设备并不总是包括指针设备。*
MID(Mobile Internet Devices)上运行的应用程序应该有和本地程序相兼容的UI,这样用户会容易使用。鉴于设备须拥有运行MIDP并满足上述要求的能力,MIDPEG认为移动设备UI不应该简单是Java UI即AWT(Abstract Windowing Tookit)。理由如下:*
AWT为桌面电脑而设计并针对这些设备做了优化,所以它同样受到这个基础(针对桌面电脑)的制约。*
当用户和AWT交互时,事件对象会被动态创建。这些对象是短暂存在的并只有在系统执行相关事件时才存在。基于这样一点,事件对象变成了垃圾并必须被系统GC回收。而MID设备的有限的CPU和存储子系统无法处理这种行为。*
AWT有一套基于桌面的图形集。MID设备无法提供给这个图形集所需要的图形支持。例如,AWT为窗口管理(window management)提供大量支持(例如:overlapping windows, window resize等)。MID设备只有小显示屏,它对于AWT来说没有大窗口和布局管理支持,但这些在MID设备中并部需要。*
AWT声明特定用户交互模型(user interaction model)。AWT组建集被设计来用指针设备操作(例如鼠标和输入笔)。正如前面所涉及到的,这个要求只有少部分MID设备能满足,而大部分MID设备只有一个用来用户输入的keypad。Structure of the MIDP UI APIMIDP UI逻辑上由两类API组成:高级API和低级API(high-level API & low-level API).高级API是为那些客户端部分运行在MID上的商用程序设计。对于这些应用,跨设备的可移植性很重要。为了达到这个可移植性要求,高级API使用一个高层次的抽象并提供非常少的外观上的控制。如下深入地介绍了这个抽象:*
显示到MID屏幕上的实际图像由这个抽象的实现来完成。应用不能定义组件的虚拟外观(例如形状、颜色、字体等)。*
navigation、scrolling和其它原型交互组件由这个实现来封装,并且应用不关心这些交互。*
应用不能访问具体的输入设备,像特定的独立的键(specific individual key)换句话说,当使用高级API时,潜在的实现类(未来的这个抽象的实现类)将要对设备硬件和本地UI样式做必要的适应。提供高级API的类是Screen的子类.在令一方面低级API提供了非常少的抽象。这个API为那些需要精确定位(precise placement)、图形元素控制(control of graphic elements)和对低级别输入事件进行访问的应用设计。一些应用还需要访问特别的或设备特定的特定。这种应用一个典型的例子就是一个游戏应用。使用低级别API时,一个应用可以:*
全面控制显示屏上所画的图像*
监听事件原型例如键按下和弹起。*
访问具体的按键和其它输入设备。提供低级API的类是Canvas和Graphics.基于低级API编写的应用不能保证可移植性,因为低级API提供了访问特定设备的特定细节的方法。如果应用不使用这些功能(依赖于特定设备的特定功能),它就可以被移植。强烈建议应用尽可能地只使用低级API中平台独立的部分。这意味着应用不要直接假设任何键在实际设备中是存在的,除了那些Canvas类中已经定义过的键,并且它们不依赖于特定屏幕大小。当然,应用程序游戏键事件的映射机制应该用来代替具体的键,并且应用程序应当询问屏幕的大小以使自己随之调整。Class HierarchyMIDP UI的核心抽象对象是一个可显示的对象,它封装了特定于设备的用户输入图形渲染。在同一时刻只有一个可显图形是可见的,并且用户只能看见该图形并与它的内容内容交互。Screen类是Displayable的一个子类,它关注所有用户和高级UI组件的交互。Screen的子类处理渲染、交互、遍历和滚动,应用中只有高级事件被传递。这种设计背后的两难抉择是MIDP基于不同的显示器和输入解决方案。这些不同意味着component layout, scrolling和 focus traversal在不同的设备上会有不同的实现。如果一个程序需要依赖于这些因素,那么它就不具备可移植性。简单的整个屏幕会把UI组织成为可以管理的块,这使得UI易用易学。Displayable对象分为三类:*
封装了一个复杂UI组件的Screen(例如:List或TextBox)。这些Screen的结构是预定义的,应用程序不能给这些组件再添加组件。*
可以包含Item对象的Generic screen组件(如Form类的实例)。应用可以用随意的用text、image和其它组件来组装Form对象。所以,强烈建议Form对象保持简单性这样的话它们就可以被用来包含少量的、紧密相关的UI组件。*
低等级API的显示对象。(像Canvas类的子类)每个Displayable有一个title,一个Ticker和一个依附的Command集。Display类扮演着display manager角色,它为每一个活动的MIDlet创建实例(Display实例)并提供获取设备显示能力的方法。调用Display的setCurrent()方法可以让一个Displayable处于可见(visible)。当一个Diplayable被调用了setCurrent(),它就替换了前一个处于current的Displayable.Class Overview预计大部分的应用程序都会用像List、TextBox和Alert这些预定义的构件来组织屏幕。这些类如下使用:*
List:当用户需要从预定义的选择集合中选择时用。*
TextBox: 要求文本输入时用。*
Alert: 显示包含文本和图片的临时信息。Form是一个特别的类,它用于当预定义的构件不够用的情况。例如:一个应用也许包含了2个TextField或者1个TextField和一个简单的ChoiceGroup,尽管Form类允许组件的任意组合,但是开发者还是应该始终考虑有限的显示大小和创建简单的Form。Form被设计来包容一组小量的紧密管理的UI元素。这些元素是Item的子类:ImageItem、StringItem、TextField、ChoiceGroup、Gauge和CustomItem。ImageItem和StringItem类使得F有关Form和Alert的特定操作更加简单。通过创建CustomItem的子类,开发者可以引入一个新的可见和可交互的Item。如果组件大小不适合于屏幕,那么该组件的实现就应该使得form可滚动或实现一些可以在新屏幕弹出或当用户编辑钙元素时展开的组件。Interplay with Application Manager像API中其它的资源一样,UI同样受控于MIDP应用管理器规则。UI要求来自AMS(Application management software)的以下几种状态:*
getDisplay()可以在MIDlet构造器到destroyApp()方法返回之间调用。*
Display对象始终是一致的直到destroyApp()被调用。*
Displayable对象通过setCurrent()调用时,不会被AMS改变。AMS假定应用程序遵守MIDlet事件,表现如下:*
startApp - 应用会为第一个屏幕调用setCurrent()。AMS使得当startApp()返回时Displayable真正可见。注意startApp()可以被调用多次,如果之间调用了pauseApp()。这意味着初始化不能发生,应用程序也不会偶然的用setCurrent()切换到另外一个屏幕。*
pauseApp - 应用应该尽可能地释放线程。同样地,如果当应用重新处于活动状态时要以另外一个屏幕开始,那么这个屏幕应该用setCurrent()来设置。*
destroyApp - 应用会删除所创建的对象。Event Handling用户交互导致事件,同时事件的实现通过事件相应的回调通知应用程序。有4类UI回调:*
高级API的Abstract Command*
表示单个键按下和放开的低级事件(如果指针可用的话还包括指针事件)*
Canvas类的paint()方法调用。*
Display类的callSerially()方法请求Runnable对象的run()方法调用。所有UI回调都是序列化的,所以它们永远不会并行发生。那就是说,前一个调用的任何其它的回调都被返回之前不会再有回调被调用。这个性质使应用确保前一个用户事件处理已经完成之后下一个事件才会被发送。如果多个UI回调处于等待,下一个回调会在前一个回调完成之后尽快被调用。这种实现方式保证来自callSerially()方法调用的run()方法紧随任何等待满足的重绘请求(repaint request)之后。回调序列化规则(callback serialization rule)有一个异常类,当Canvas.servicRepaints方法被调用时会抛出。这个方法导致Canvas.paint方法将被调用并等待它完成。即使servicRepaints的调用者是在一个活动回调中的它本身这种情况也会发生。以下是深入的讨论:/javame/reference/apis/jsr118/javax/microedition/lcdui/package-summary.html#concurrency以下回调经过互相关联的序列化:注意:Timer事件不被认为是UI事件。Timer回调可以和UI事件回调同步执行,尽管安排在同一个Timer上的TimerTask回调互相之间是序列化过的。应用程序使用timer时需要保护它们的数据不被其它timer线程和UI事件回调同事访问。作为选择,应用程序可以拥有它们自己的使用Display.callSerially的timer回调,这样它就可以用用UI事件回调序列化的timer事件来触发工作。Abstract Commands由于MIDP UI是高度抽象的,它不能支持任何实在的用户交互技术像软按钮或菜单。同样,像焦点遍历或滚动条这样的低级用户交互对于应用程序而言是不可见的。MIDP应用定义Command,应用实现会列出基于软按键、菜单或为该设备指定的所有适当的机制。用Displayable类的addCommand方法可以将Command安装到Displayable(Canvas 或 Screen)。设备的本地类型会假定Command的特定类型被放置在标准位置上。例如:“go-back”操作会始终映射到右侧软按键。Command类允许应用程序来传达一个指示给实现类,这样这些标准映射就说生效。Command实现实际上不实现任何Command语义。一个Command的属性仅仅被用来映射到UI。一个Command的实际语义永远都是you程序里的CommandListener来实现。Command对象拥有的属性:*
Lable: 作为提示显示给用户。一个单个的Command有2个版本的lable:长和短。具体实现决定长、短lable和给定的情形是否适应。例如:一种实现可以选择一个软按键附件的已给定的Command的短版本和一个菜单中的该Command的长版本。*
Type:一个Command的用途。具体实现会使用这个Command的type来把它准确的映射到设备的UI中。例如,拥有近似类型的Command可能会发现在UI中特定位置上离的很近。经常设备会有Command映射位置和特定操作的策略。例如,一个“backward navigation” Command可能在某个特定设备上会被永远的映射到右侧软按键上,但是它又会被另外一个不同设备映射到左侧软按键上。Command类提供固定的Command type来提供给MIDlet告知设备这个Command的实现意图的能力。应用程序可以使用BACK Command type为Command来完成backward navigation操作。上面所提到的设备,它们的type信息会被用来声明给特定的软按键。*
优先权:定义同类型Command之间的相对重要性。一个低优先权值的Command比同样类型的高优先权值的Command更重要。如果可能,相比一个不重要的Command,一个更重要的Command会先执行,或更易取得。
如果您想提高自己的技术水平,欢迎加入本站官方1号QQ群:&&,&&2号QQ群:,在群里结识技术精英和交流技术^_^
本站联系邮箱:

我要回帖

更多关于 xmpp ios 的文章

 

随机推荐