当前位置: 首页 > news >正文

J2ME最佳实践之屏幕导航

作者:asklxf 文章来源:http://www.j2medev.com/Article/ShowArticle.asp?ArticleID=964

屏幕导航

除了游戏程序,在通常的MIDP应用程序中,通常会有很多个Screen或Canvas,这些屏幕一般靠命令来实现切换,比如用户点击“Next”应该跳到下一屏,点击“Back”应该返回到上一屏。当屏幕数量相当可观时,如何在各个屏幕之间导航就值得好好考虑了。

经典的MVC模式可用于屏幕导航,Model用于存储应用程序数据,而View则是各个Displayable对象,Controller需要单独的一个类实现。由于MIDlet类本身在生命周期内就只有一个实例,因此MIDlet类就非常适合作为Controller。SUN在blueprints示例程序SmartTicket中应用了非常复杂的MVC,完全可以满足MIDP应用程序的导航需要,但是可以看出,缺点是很明显的:

一是每一个事件都需要一个唯一标识,switch-case语句会随着屏幕的增加而增加,Controller变得难以维护。二是Controller引用了所有的View,这些View在程序启动时就被初始化导致很大的内存开销,而不管它们是否会被显示。三是大量的Model对象以及异常处理都使得整个应用程序的逻辑大大复杂。

实际上,MIDP应用程序的很多屏幕并不需要复杂的Controller和Model,我们的目标是满足基本的灵活性的同时保持结构简单。因此,另外两种导航方法是用二叉树和堆栈实现,这里我们只讨论用堆栈实现的MIDP导航框架,其基本思想是:每当前进到下一个屏幕时,先将下一个屏幕压栈,然后再显示;当返回到上一个屏幕时,先从堆栈中弹出当前屏幕,再从堆栈中取出上一个屏幕并显示。因此,每个屏幕只需要指定要显示的下一个屏幕,而不需记住上一个屏幕。这种堆栈导航模型特别适合有规律的“前进”、“后退”屏幕。

由于MIDlet类运行期只有一个实例,因此,使用MIDlet类作为控制器相当合适。此外,我们在一个静态变量中保存了MIDlet实例,使得访问MIDlet更加方便:

public class ControllerMIDlet extends MIDlet {
private static ControllerMIDlet instance = null;

private Display display = null;
private Stack ui = new Stack();

public ControllerMIDlet() { instance = this; }

protected void startApp() {}
protected void pauseApp() {}
protected void destroyApp(boolean unconditional) {}

public static void goBack() {
instance.ui.pop();
Object obj = instance.ui.peek();
instance.display.setCurrent((Displayable)obj);
}

public static void forward(Displayable next) {
instance.ui.push(next);
instance.display.setCurrent(next);
}
}

让我们更详细地研究一下实际的应用程序可能出现的几种屏幕跳转情况。最简单的情况是,从一个屏幕前进到另一个屏幕,且返回时仍回到原先的屏幕,这种情况完全符合堆栈的FIFO特点,可以直接调用ControllerMIDlet的forward和goBack方法即可。例如,要显示一个帮助屏幕:

对于一个联网的应用程序,另一种情况是有一个暂时的等待屏幕。下面是一个在线浏览图片的屏幕:

与上面的情况所不同的是,如果用户在屏幕3选择“返回”,则应当回到屏幕1而不是屏幕2,因此,对于屏幕2到屏幕3的切换,就不能forward,我们使用replace,抛弃屏幕2,从而实现屏幕3直接可以goBack到屏幕1:

public static void replace(Displayable next) {
instance.ui.pop();
instance.ui.push(next);
instance.display.setCurrent(next);
}

堆栈的变化如下:

对于某些更为复杂的情况,例如,登录过程,如果允许用户选择自动登录,则屏幕跳转如下:

如果用户不选择自动登录,则屏幕跳转如下:

对于这种情况,解决方案是,即使用户选择了自动登录,LoginUI屏幕也要被压入堆栈中,但是不显示出来,因此,我们定义了另一个forward(Displayable d1, Displayable d2)方法,它将d1和d2依次压入堆栈,但只显示d2。在返回时,如果用户取消,则返回到LoginUI。总之,通过定义多个导航方法,就可以实现各种操作。

这种基于堆栈的导航模型非常适用于有规律的“前进”,“后退”屏幕,而且只在需要的时候生成新的屏幕。无需关心屏幕状态,因为返回时上一个屏幕的状态被完整地保存在堆栈中。

堆栈模型的缺点是数据由不同的屏幕处理,对于一些流程而言,可能需要将每个屏幕的数据依次传递给下一个屏幕,越往后的屏幕其构造方法的参数可能也越多。

对于联网操作等涉及到多线程等待屏幕的情况,我们将在后面给出一个完整的解决方案,并集成到堆栈导航框架中,使应用程序本身完全不用涉及到多线程联网操作,只需专注于自身逻辑。

相关文章:

  • 微信小程序真机调试连接不到后台服务器,解决微信小程序wepy真机预览跟本地表现不一样,数据变化了视图没变化...
  • J2ME最佳实践之联网开发
  • 365gps怎样修改服务器,gps365定位器怎么用(gps定位器ID号怎么获取)
  • J2ME最佳实践之RMS操作
  • 在MIDP2.0中操作图片像素
  • 配置 vue 环境
  • 介绍J2ME的几个重要概念
  • 谷歌浏览器插件
  • 基于MIDP实现ResourceBundle类
  • Node.js 基础-01
  • vscode保存代码,自动按照eslint规范格式化代码设置(vscode最新版配置)
  • 关注J2ME WTK2.2新特性
  • 高级前端面试题
  • 介绍MIDP的属性问题
  • 破解 vue3.x 新特性
  • SegmentFault for Android 3.0 发布
  • [iOS]Core Data浅析一 -- 启用Core Data
  • gf框架之分页模块(五) - 自定义分页
  • iOS帅气加载动画、通知视图、红包助手、引导页、导航栏、朋友圈、小游戏等效果源码...
  • Joomla 2.x, 3.x useful code cheatsheet
  • mongo索引构建
  • React Native移动开发实战-3-实现页面间的数据传递
  • React-redux的原理以及使用
  • TypeScript迭代器
  • WebSocket使用
  • 分享一个自己写的基于canvas的原生js图片爆炸插件
  • 服务器从安装到部署全过程(二)
  • 如何编写一个可升级的智能合约
  • FaaS 的简单实践
  • LIGO、Virgo第三轮探测告捷,同时探测到一对黑洞合并产生的引力波事件 ...
  • ​​​​​​​Installing ROS on the Raspberry Pi
  • #pragma once
  • $forceUpdate()函数
  • $HTTP_POST_VARS['']和$_POST['']的区别
  • %@ page import=%的用法
  • (3)nginx 配置(nginx.conf)
  • (Mirage系列之二)VMware Horizon Mirage的经典用户用例及真实案例分析
  • (poj1.3.2)1791(构造法模拟)
  • (动手学习深度学习)第13章 计算机视觉---微调
  • (二)pulsar安装在独立的docker中,python测试
  • (四)Linux Shell编程——输入输出重定向
  • (五)MySQL的备份及恢复
  • .gitignore
  • .NET NPOI导出Excel详解
  • .NET 中使用 TaskCompletionSource 作为线程同步互斥或异步操作的事件
  • .net/c# memcached 获取所有缓存键(keys)
  • .Net多线程总结
  • .net最好用的JSON类Newtonsoft.Json获取多级数据SelectToken
  • @require_PUTNameError: name ‘require_PUT‘ is not defined 解决方法
  • [BUUCTF 2018]Online Tool(特详解)
  • [cocos2d-x]关于CC_CALLBACK
  • [Google Guava] 2.1-不可变集合
  • [hibernate]基本值类型映射之日期类型
  • [HTML]Web前端开发技术7(HTML5、CSS3、JavaScript )CSS的定位机制——喵喵画网页
  • [IM] [Webhook] Webhook实现IM平台机器人