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() 这个东西并不是我的,但是却要我去摧毁,那么肯定也会抛出上面的异常了!
MIDlet工作原理的更多相关文章
- 菜鸟学Struts2——Struts工作原理
在完成Struts2的HelloWorld后,对Struts2的工作原理进行学习.Struts2框架可以按照模块来划分为Servlet Filters,Struts核心模块,拦截器和用户实现部分,其中 ...
- 【夯实Nginx基础】Nginx工作原理和优化、漏洞
本文地址 原文地址 本文提纲: 1. Nginx的模块与工作原理 2. Nginx的进程模型 3 . NginxFastCGI运行原理 3.1 什么是 FastCGI ...
- HashMap的工作原理
HashMap的工作原理 HashMap的工作原理是近年来常见的Java面试题.几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道HashTable和HashMap之间 ...
- 【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之RAC 工作原理和相关组件(三)
RAC 工作原理和相关组件(三) 概述:写下本文档的初衷和动力,来源于上篇的<oracle基本操作手册>.oracle基本操作手册是作者研一假期对oracle基础知识学习的汇总.然后形成体 ...
- ThreadLocal 工作原理、部分源码分析
1.大概去哪里看 ThreadLocal 其根本实现方法,是在Thread里面,有一个ThreadLocal.ThreadLocalMap属性 ThreadLocal.ThreadLocalMap t ...
- Servlet的生命周期及工作原理
Servlet生命周期分为三个阶段: 1,初始化阶段 调用init()方法 2,响应客户请求阶段 调用service()方法 3,终止阶段 调用destroy()方法 Servlet初始化阶段: 在 ...
- 代码管理工具 --- git的学习笔记二《git的工作原理》
通过几个问题来学习代码管理工具之git 一.git是什么?为什么要用它?使用它的好处?它与svn的区别,在Mac上,比较好用的git图形界面客户端有 git 是分布式的代码管理工具,使用它是因为,它便 ...
- 【原】Learning Spark (Python版) 学习笔记(三)----工作原理、调优与Spark SQL
周末的任务是更新Learning Spark系列第三篇,以为自己写不完了,但为了改正拖延症,还是得完成给自己定的任务啊 = =.这三章主要讲Spark的运行过程(本地+集群),性能调优以及Spark ...
- 浏览器内部工作原理--作者:Tali Garsiel
本篇内容为转载,主要用于个人学习使用,作者:Tali Garsiel 一.介绍 浏览器可以被认为是使用最广泛的软件,本文将介绍浏览器的工作原理,我们将看到,从你在地址栏输入google.com到你看到 ...
随机推荐
- Hadoop就业面试题
----------------------------------------------------------------------------- [申明:资料来源于互联网] 本文链接:htt ...
- 大话XML解析
之前我写过一篇关于xml解析的文章:http://blog.csdn.net/sdksdk0/article/details/50749326.今天这篇文章主要是进一步加深对xml基础的理解了使用,毕 ...
- APP中一种在Java层实现的简单守护进程方式
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52779986 守护进程是一个黑色 ...
- 改进版getpass库
编程伊始 正式实施 改进版 源码 以数字显示 以自定义分隔符delimiter显示 如何使用 下载及安装 在您的代码中使用 源码下载 总结 用过Linux的都知道,尤其是进行使用包管理软件类似于apt ...
- ListView下拉刷新上拉加载更多实现
这篇文章将带大家了解listview下拉刷新和上拉加载更多的实现过程,先看效果(注:图片中listview中的阴影可以加上属性android:fadingEdge="none"去掉 ...
- CSS简单使用
CSS简单使用 标签 : 前端技术 CSS(Cascading Style Sheet : 层叠样式表单)用来定义网页显示效果. 可以解决HTML代码对样式定义的重复,提高后期样式代码的可维护性,并增 ...
- PGM:无向图模型:马尔可夫网
http://blog.csdn.net/pipisorry/article/details/52489321 马尔可夫网 马尔可夫网在计算机视觉领域通常称为马尔可夫随机场(Markov random ...
- [nginx] 对UA为空的请求返回403
nginx blocking blank user agent . sometime apps' backgroud request always visit a url, and these req ...
- FFmpeg源代码简单分析:结构体成员管理系统-AVClass
===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...
- FFmpeg源代码简单分析:常见结构体的初始化和销毁(AVFormatContext,AVFrame等)
===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...