MIDlet工作原理
题记 : 现在的J2ME用户已经是日益减少 , 开发也在转型! 无奈之下也不得不写下这系列文章来别了j2me ,也是对过去的一些总结吧!
①: 所有Kjava必须会继承自javax.microedition.midlet.MIDlet类的。其中定义了三个抽象方法(abstract),因此我们撰写的MIDlet必须实现它们。这三个抽象方法是:
1. startApp() 转到运作状态
2. pauseApp() 转到停止状态
3. destroyApp() 转到消灭状态
应用程序管理器通过这三个抽象方法来控制MIDlet的生命周期。因此,所有的MIDlet都必须实现这三个方法 !
②:两种控制应用程序的生命周期的方式
1. 由应用程序管理器来控制(硬控制)
生命周期
如上图可知midlet在进入某个状态之前都会调用相应的函数然后进入该状态。 这都是应用程序管理器调用的,但是设计者考虑到了如果程序员自己调用了这里面的情况。
讨论一: 如果程序员自己调用了这里面的情况的话应用程序管理器会做如何的改变呢?
官方文档如此回答: 通常不会发生错误,但是也不会造成状态的转换,只是当成一个单纯的函数调用而已
在此做了一个小的案例来说明一下 :
情况一 :
public class MidTest extends MIDlet {
public MidTest() {
System.out.println("MidTest()");
}
protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
System.out.println("destroyApp()");
}
protected void pauseApp() {
System.out.println("pauseApp()");
}
protected void startApp() throws MIDletStateChangeException {
System.out.println("startApp()");
destroyApp(true);
}
}
当我们程序员自己在startApp() 里面调用destroyApp(true);(这个函数的参数后面会讲到) 时,它的结果如下:
MidTest() startApp() destroyApp()
但是程序并没有退出! 说明了一个情况就是 : 自己调用的时候是不会进行状态的切换的!
情况二:当我们关闭程序的时候得到的结果是: destroyApp() 说明了当关闭程序的时候应用程序管理器会调用此方法的!
讨论二 :如何合理利用startApp()?pauseApp() ? destroyApp(boolean arg0) ?
从上图的生命周期可以看到startApp()这个函数是不止一次被调用的(第一次new) 当恢复了pause后也会进入这种状态。所以做为开发人员的我们那些没有必要重新初始化的操作(特别是加载一些资源的时候)不要放到这里面,以免浪费时间! 最好的做法就是:放在构造函数做初始化动作
应用程序管理器会因为某些状况,必须让MIDlet停止运作。例如手机来电,或者闹铃响了,或者用户强行切换到其他程序执行。在这些情况吓,为了避免MIDlet占用太多系统资源,应用程序管理器会调用该MIDlet的pauseApp(),这时应该在pauseApp()之中适时的释放一些非必需的资源,等到返回到运作状态时,应用程序管理器会重新调用startApp(),这时再将这些被释放的资源重新加载
当MIDlet进入停止状态时,不应该使用任何资源。如果应用程序管理器调用pauseApp()时产生异常,MIDlet就应该立刻进入消灭状态。同样的情况也发生在destroyApp(),通常调用此方法时,表示MIDlet要被关闭了。所以,应该在这里释放MIDlet所分配的资源。只要MIDlet进入消灭状态,就无法再回头。如果时系统自己调用destroyApp(),那么在其执行时万一发生异常,这些异常将被忽略,MIDlet一样会被关闭。
2. 由程序员来控制(软控制) :由程序员来决定是否退出程序
当MIDlet主动要将MIDlet的状态由运作状态变成停止状态,那么我们直接调用pauseApp()函数,只会执行pauseApp()之中的程序代码,无法改变MIDlet的状态,MIDlet必须调用notifyPaused()来通知应用程序管理器,应用程序管理器收到通知后,才会判断是否要让MIDlet进入停止状态。
由MIDlet调用notifyPaused()与应用程序管理器主动要求停止,两者是有所差别的。主要在于应用程序管理器主动要求停止时,pauseApp()会被调用;由MIDlet调用notifyPaused()时,pauseApp()不会被调用。但两者都会让MIDlet进入停止状态,所以在MIDlet自己调用notifyPaused()之前,最好自己也先调用pauseApp()比较合适。
实例如下:
public class MidTest extends MIDlet {
public MidTest() {
System.out.println("MidTest()");
}
protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
System.out.println("destroyApp()");
}
protected void pauseApp() {
System.out.println("pauseApp()");
}
protected void startApp() throws MIDletStateChangeException {
System.out.println("startApp()");
notifyPaused() ;
}
结果是 :
MidTest() startApp() 表明了程序员自己调用了notifyPaused() 其实并没有调用pauseApp() 所以这里最好的写法是在notifyPaused() 之前调用pauseApp() ;
同样的情况也发生在notifyDestroyed()与destroyApp()。除非时系统强制关闭MIDlet,否则最好MIDlet先调用destroyApp(),然后再调用notifyDestroyed(),请应用程序管理器帮我们将MIDlet转换到消灭状态,最后结束MIDlet的运作。destoryApp()有个布尔值作为参数,根据MIDP规范,如果传入true,那么MIDlet不管如何应该强制无条件释放所有资源,然后让应用程序管理器结束MIDlet的运作,这属于系统或硬件强制关闭MIDlet的情形。如果用户调用notifyDestoryed()来结束MIDlet,那么在调用destroyApp()时,最好传入false,代表这并非系统或硬件强制关闭,这时如果MIDlet不希望结束执行,可以通过抛出MIDletStateChangeException异常告知调用者:我还不想被消灭,稍后再试。
③:总结:
从上面我们也可以看出startApp()、pauseApp()以及destroyApp()并非控制MIDlet生命周期的函数,它们只是一个提供我们初始化资源、释放资源的地方而已。真正的地方还是软控制里面的那些函数!
明天继续这个系列的系统原理,谢谢大家!
补充: 今天看到论坛上有朋友提出了这样一个问题 : 两个midlet的切换!
我们知道应用程序初始化后就会在建立一个对应的虚拟机,并创建一个对应的虚拟机实例! 如果向如下来创建的话:
public class Test extends MIDlet {
static Display display ;
public Test()
{
display = Display.getDisplay(this) ;
System.out.println("Test()");
}
protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
System.out.println("destroyApp ");
}
protected void pauseApp() {
}
protected void startApp() throws MIDletStateChangeException {
System.out.println("startApp ");
new Test2() ;
}
}
那么在new Test2() 这一步的时候其实原来的虚拟机实例是没有消失的。这时就是试图在一个虚拟机里创建两个实例那是不允许的! 系统就会抛出:
java.lang.SecurityException: Application not authorized to access the restricted API(访问受限的API)
那么另一个问题来了。你可能会说那么我们先将Test 使用notifyDestroyed() ;进行销毁。然后再次创建就是一个实例了
其实不然,正如我上面讲解软控制的时候提到的。notifyDestroyed() 这个东西只是提醒应用程序管理器,我要死了。把资源都释放了吧。但是应用程序管理器会去检测一下还有没有存活的东西,然后才回去摧毁。如果你这样来调用的话!
protected void startApp() throws MIDletStateChangeException {
System.out.println("startApp ");
notifyDestroyed() ;
new Test2() ;
}
那么当Test()的应用程序管理器检查到了notifyDestroyed() 正准备释放资源了。才发现new Test2() 这个东西并不是我的,但是却要我去摧毁,那么肯定也会抛出上面的异常了!
- 如何使用Intellij搭建Spark开发环境
- 如何重置Cloudera Manager的admin密码
- 如何在CDH集群安装Anaconda&搭建Python私有源
- 如何使用Python Impyla客户端连接Hive和Impala
- 如何在Windows Server2008搭建DNS服务并配置泛域名解析
- 如何通过CM API优雅的获取元数据库密码
- CM启动报InnoDB engine not found分析
- 如何在Hue中使用Sentry
- 如何在Redhat中配置R环境
- 如何在Redhat中安装R的包及搭建R的私有源
- 什么是sparklyr
- 如何利用Dnsmasq构建小型集群的本地DNS服务器
- Cloudera Labs中的Phoenix
- 如何在CDH中使用Phoenix
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Java——类集框架:Set集合接口的详解及应用举例
- 如何有效地进行代码 Review?
- Java——对象序列化
- Android——MPAndroidChart折线图/柱状图/饼形图的使用
- Java——对String类型的时间进行加减操作
- Java——枚举基础应用总结(多例设计模式、Enum类、枚举的实际应用)
- Java——Annotation注解基本总结(简介、覆写、过期声明、压制警告)
- JavaWeb——一文快速入门BootStrap(栅格系统、全局CSS样式、组件、插件、基于BootStrap的官网案例实战)
- JavaWeb——XML入门详解(概述、语法、约束、Jsoup解析、Xpath解析)
- JavaWeb——CSS应用实例详解(概述、语法、选择器、属性、用户登录界面实例)
- JavaWeb——JavaScript精讲之事件监听机制与表单校验案例实战
- Java——扩展概念(匿名内部类、包装类、装箱与拆箱、数据类型的转换)
- Java——接口的基本总结(基本定义、使用接口定义标准、工厂设计模式、代理设计模式、抽象类与接口的区别)
- JavaWeb——HTML表单标签详解(input、label、select、textarea)
- Java——设计辅助概念(final关键字、对象多态性基本概念)