题记 :  现在的J2ME用户已经是日益减少 , 开发也在转型! 无奈之下也不得不写下这系列文章来别了j2me ,也是对过去的一些总结吧!

①: 所有Kjava必须会继承自javax.microedition.midlet.MIDlet类的。其中定义了三个抽象方法(abstract),因此我们撰写的MIDlet必须实现它们。这三个抽象方法是:

1.     startApp()   转到运作状态

2.     pauseApp()   转到停止状态

3.     destroyApp() 转到消灭状态

 应用程序管理器通过这三个抽象方法来控制MIDlet的生命周期。因此,所有的MIDlet都必须实现这三个方法 !

②:两种控制应用程序的生命周期的方式

   1.  由应用程序管理器来控制(硬控制)

生命周期

如上图可知midlet在进入某个状态之前都会调用相应的函数然后进入该状态。 这都是应用程序管理器调用的,但是设计者考虑到了如果程序员自己调用了这里面的情况。

 讨论一: 如果程序员自己调用了这里面的情况的话应用程序管理器会做如何的改变呢?

官方文档如此回答:  通常不会发生错误,但是也不会造成状态的转换,只是当成一个单纯的函数调用而已

       在此做了一个小的案例来说明一下 :

情况一 :

  1. public class MidTest extends MIDlet {
  2. public  MidTest() {
  3. System.out.println("MidTest()");
  4. }
  5. protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
  6. System.out.println("destroyApp()");
  7. }
  8. protected void pauseApp() {
  9. System.out.println("pauseApp()");
  10. }
  11. protected void startApp() throws MIDletStateChangeException {
  12. System.out.println("startApp()");
  13. destroyApp(true);
  14. }
  15. }

当我们程序员自己在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()比较合适。

 实例如下: 

  1. public class MidTest extends MIDlet {
  2. public  MidTest() {
  3. System.out.println("MidTest()");
  4. }
  5. protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
  6. System.out.println("destroyApp()");
  7. }
  8. protected void pauseApp() {
  9. System.out.println("pauseApp()");
  10. }
  11. protected void startApp() throws MIDletStateChangeException {
  12. System.out.println("startApp()");
  13. notifyPaused() ;
  14. }

结果是 :

   

  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的切换!

我们知道应用程序初始化后就会在建立一个对应的虚拟机,并创建一个对应的虚拟机实例! 如果向如下来创建的话:

  1. public class Test extends MIDlet {
  2. static Display display ;
  3. public Test()
  4. {
  5. display = Display.getDisplay(this) ;
  6. System.out.println("Test()");
  7. }
  8. protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
  9. System.out.println("destroyApp ");
  10. }
  11. protected void pauseApp() {
  12. }
  13. protected void startApp() throws MIDletStateChangeException {
  14. System.out.println("startApp ");
  15. new Test2() ;
  16. }
  17. }

那么在new Test2() 这一步的时候其实原来的虚拟机实例是没有消失的。这时就是试图在一个虚拟机里创建两个实例那是不允许的! 系统就会抛出:

java.lang.SecurityException: Application not authorized to access the restricted API(访问受限的API)

那么另一个问题来了。你可能会说那么我们先将Test 使用notifyDestroyed() ;进行销毁。然后再次创建就是一个实例了

其实不然,正如我上面讲解软控制的时候提到的。notifyDestroyed()  这个东西只是提醒应用程序管理器,我要死了。把资源都释放了吧。但是应用程序管理器会去检测一下还有没有存活的东西,然后才回去摧毁。如果你这样来调用的话!

  1. protected void startApp() throws MIDletStateChangeException {
  2. System.out.println("startApp ");
  3. notifyDestroyed() ;
  4. new Test2() ;
  5. }

那么当Test()的应用程序管理器检查到了notifyDestroyed() 正准备释放资源了。才发现new Test2() 这个东西并不是我的,但是却要我去摧毁,那么肯定也会抛出上面的异常了!

MIDlet工作原理的更多相关文章

  1. 菜鸟学Struts2——Struts工作原理

    在完成Struts2的HelloWorld后,对Struts2的工作原理进行学习.Struts2框架可以按照模块来划分为Servlet Filters,Struts核心模块,拦截器和用户实现部分,其中 ...

  2. 【夯实Nginx基础】Nginx工作原理和优化、漏洞

    本文地址 原文地址 本文提纲: 1.  Nginx的模块与工作原理    2.  Nginx的进程模型    3 . NginxFastCGI运行原理        3.1 什么是 FastCGI   ...

  3. HashMap的工作原理

    HashMap的工作原理   HashMap的工作原理是近年来常见的Java面试题.几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道HashTable和HashMap之间 ...

  4. 【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之RAC 工作原理和相关组件(三)

    RAC 工作原理和相关组件(三) 概述:写下本文档的初衷和动力,来源于上篇的<oracle基本操作手册>.oracle基本操作手册是作者研一假期对oracle基础知识学习的汇总.然后形成体 ...

  5. ThreadLocal 工作原理、部分源码分析

    1.大概去哪里看 ThreadLocal 其根本实现方法,是在Thread里面,有一个ThreadLocal.ThreadLocalMap属性 ThreadLocal.ThreadLocalMap t ...

  6. Servlet的生命周期及工作原理

    Servlet生命周期分为三个阶段: 1,初始化阶段  调用init()方法 2,响应客户请求阶段 调用service()方法 3,终止阶段 调用destroy()方法 Servlet初始化阶段: 在 ...

  7. 代码管理工具 --- git的学习笔记二《git的工作原理》

    通过几个问题来学习代码管理工具之git 一.git是什么?为什么要用它?使用它的好处?它与svn的区别,在Mac上,比较好用的git图形界面客户端有 git 是分布式的代码管理工具,使用它是因为,它便 ...

  8. 【原】Learning Spark (Python版) 学习笔记(三)----工作原理、调优与Spark SQL

    周末的任务是更新Learning Spark系列第三篇,以为自己写不完了,但为了改正拖延症,还是得完成给自己定的任务啊 = =.这三章主要讲Spark的运行过程(本地+集群),性能调优以及Spark ...

  9. 浏览器内部工作原理--作者:Tali Garsiel

    本篇内容为转载,主要用于个人学习使用,作者:Tali Garsiel 一.介绍 浏览器可以被认为是使用最广泛的软件,本文将介绍浏览器的工作原理,我们将看到,从你在地址栏输入google.com到你看到 ...

随机推荐

  1. PHP 文件下载 浅析

    无控制类型 avi文件 rar文件 mp4MP3图片等会被直接解析 核心代码 类型 长度 实现函数 优化 原始下载文件的名称 优化后的文件下载名称 总结 文件下载的功能对一个网站而言基本上是必备的了, ...

  2. ROS机器人程序设计(原书第2版)补充资料 教学大纲

    ROS机器人程序设计(原书第2版) 补充资料 教学大纲 针对该书稍后会补充教学大纲.教案.多媒体课件以及练习题等. <ROS机器人程序设计>课程简介 课程编号:XXXXXX 课程名称:RO ...

  3. PHP学习(3)—在HTML中嵌入PHP

    我们以一个提交订单和显示订单信息的例子为学习PHP的开始.这个例子包含两个文件.一个提交订单的html文件:orderform.html,一个显示订单信息的php文件:processorder.php ...

  4. 如何正确使用const、static、extern

    转自:http://www.jianshu.com/p/2fd58ed2cf55 前言 本篇文章主要介绍在开发中怎么使用const.static.extern关键字. 一.const 与宏的区别: c ...

  5. Linux 环境下一些常用命令(四)

    转自 http://www.oschina.net/translate/20-advanced-commands-for-middle-level-linux-users 31. 命令: rm 'rm ...

  6. Android开发学习之路--UI之初体验

    之前都是学习Activity,对于布局都没有做过学习,这里就简单学习下吧.下面看下Android Studio下有哪些控件: 这里分为Widgets,Text Fields,Containers,Da ...

  7. Cocos2D中Node的userObject实例变量使用时一个要注意的地方

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 我们知道在Cocos2D中,CCNode对象有一个ivar为us ...

  8. 如何在Cocos2D游戏中实现A*寻路算法(七)

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...

  9. Java项目案例:酒店前台客服管理系统

    import java.util.Scanner; public class HelloWorld { public static void main(String[] args){ String [ ...

  10. c# 单元测试工程如何取得当前项目路径

    前言: C#工程项目中有些配置文件,数据文件等不是C#工程文件,但是程序中需要访问,如果写成绝对路径不利于程序的迁移,所以必须写成相对路径.取得相对路径的方法很多,网上的例子也很多,基本上是七种吧,这 ...