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() 这个东西并不是我的,但是却要我去摧毁,那么肯定也会抛出上面的异常了!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Golang语言社区

go-concurrent-programming.md

最近在看《Programming in Go》, 其中关于并发编程写得很不错, 受益非浅, 其中有一些例子是需要多思考才能想明白的, 所以我打算记录下来, 强化...

3909
来自专栏圆方圆学院精选

【刘文彬】RPC的基础:调研EOS插件http_plugin

原文链接:醒者呆的博客园,https://www.cnblogs.com/Evsward/p/httpPlugin.html

1091
来自专栏林冠宏的技术文章

Golang, 以17个简短代码片段,切底弄懂 channel 基础

(原创出处:https://cloud.tencent.com/developer/user/1148436/activities) 前序:   因为打算自己搞...

3805
来自专栏王亚昌的专栏

路由查找算法优化心得

    项目代码中有一个基础类库,用于解析client到server的路由配置文件,同时管理长连接。路由配置文件格式大致如下所示:

992
来自专栏阮一峰的网络日志

PHP最佳实践

虽然名字叫《PHP最佳实践》,但是它主要谈的不是编程规则,而是PHP应用程序的合理架构。

2151
来自专栏高性能服务器开发

(一)Redis结构解析

从今天起,本人将会展开对Redis源码的学习,Redis的代码规模比较小,非常适合学习,是一份非常不错的学习资料,数了一下大概100个文件左右的样子,用的是C...

2854
来自专栏散尽浮华

Saltstack自动化操作记录(2)-配置使用

之前梳理了Saltstack自动化操作记录(1)-环境部署,下面说说saltstack配置及模块使用: 为了试验效果,再追加一台被控制端minion机器192....

25211
来自专栏青玉伏案

设计模式(六):控制台中的“命令模式”(Command Pattern)

今天的博客中就来系统的整理一下“命令模式”。说到命令模式,我就想起了控制台(Console)中的命令。无论是Windows操作系统(cmd.exe)还是Linu...

2029
来自专栏欧阳大哥的轮子

深入iOS系统底层之XCODE对汇编的支持介绍

一个好的IDE不仅要提供舒适简洁和方便的源代码编辑环境,还要提供功能强大的调试环境。XCODE是目前来说对iOS应用开发支持的最好的IDE(虽然Visual S...

942
来自专栏LanceToBigData

JavaWeb(一)Servlet中乱码解决与转发和重定向的区别

前言   前面其实已经把Servlet中所有的内容都介绍完了,这篇讲补充一点乱码和重定向与转发之间的区别! 一、request请求参数出现乱码问题 1.1、ge...

26510

扫码关注云+社区