Just An Application

June 16, 2009

What’s New In MIDP 3.0 ? Part 10: The MIDlet Lifecycle

Filed under: Java, JME, MIDlets, MIDP, MIDP3, MIDP3Issues — Tags: , , , , , , — Simon Lewis @ 9:09 am

1. The MIDlet Lifecycle

The MIDlet lifecycle has been changed in MIDP 3.0. Although the changes can be summarized fairly succinctly there are number of problems with the specification which mean that it is not entirely clear what is supposed to be going on at the detailed level.

To begin with I will describe what the lifecycle now is, given what I take the intent of the changes to be, without getting into too many details and getting bogged down in the problems. I cover those in following section.

1.1 The Changes

MIDlets are no longer paused, cannot pause themselves, and consequently do not need to ask to be resumed. In addition a MIDlet can no longer decline to be destroyed.

As a result the MIDlet methods

  • notifyPaused()
  • pauseApp()
  • resumeRequest()

are all deprecated, and the pauseApp() method is no longer abstract.

1.2 The Lifecycle of a MIDP 3.0 MIDlet

If we make the not unreasonable assumption that a MIDlet written against the MIDP 3.0 spec will not call any of the deprecated lifecycle methods, and ignoring errors and edge-cases, then the lifecycle of a MIDlet is very simple

  • it is constructed via a call to its constructor
  • it is then started via a call to its startApp() method
  • it then runs until it is destroyed via a call to its destroyApp() method, or it destroys itself and calls its notifyDestroyed() method

1.2 The Lifecycle of a Legacy MIDlet

A legacy MIDlet, that is one written to run under MIDP 1.0 or MIDP 2.0, running under MIDP 3.0, may call notifyPaused() and/or resumeRequest(). This complicates the lifecycle slightly. Ignoring errors and edge-cases as before, then the lifecycle of a legacy MIDlet
in MIDP 3.0 is as follows

  • it is constructed via a call to its constructor
  • it is then started via a call to its startApp() method
  • it then runs
  • if while running it calls its notfifyPaused() method then its startApp() method is called immediately
    and it continues to run.
  • if while running it calls its notifyDestroyed() method then the MIDlet terminates.
  • if the MIDlet’s destroyApp() method is called, then on completion, successful or as the result of an exception the MIDlet terminates.

If it calls its notfifyPaused() method other than whilest running the call is ignored.

If at any point it calls its resumeRequest() method the call is ignored.

2. Issues With The Specification Of The MIDlet Lifecycle In The MIDP 3.0 Specification

2.1 The MIDlet Lifecycle State Diagram

Given the apparent simplicity of the MIDlet lifecycle, the state diagram included in the javax.microedition.midlet package documentation looks suprisingly busy. Indeed at first glance it is difficult to see the differences between it and the version in the MIDP 2.1 specification. The differences do become apparent on closer examination but so do the issues.

I am assuming that the diagram is intended to be UML, or UML-like, since the key explicitly mentions UML. On that basis there turn out to be a number of problems. To make it easier to describe them I have converted the diagram into per-state tables, as follows.

Assuming UML, then according to the UML Reference Manual the body of each state should contain

a list of internal actions or activities performed in response to events received while the object is in the state,
without changing state.

These are called internal transitions. An internal transition is of the form

    [<event-name>]["(" <arguments> ")"]["[" <guard-condition> "]"]["/" <action-expression>]

A transition to another state is of the form

    [<name> ":"][<event-name>][<parameter-list>][<guard-condition>]["/" <action-list>]

For each state in the diagram I have constructed a table of internal transitions and a table of transitions to other states, except
where that turns out not to be possible.

2.1.1 The <Initial> State

Problems

The transition

    / AMS: Create MIDlet() [RuntimeException thrown]

is not legal UML.

Moving the guard to the right place, on the left, gives

    [RuntimeException thrown] / AMS: Create MIDlet() 

which can be read as saying

if a RuntimeException occurs then the action ‘AMS: Create MIDlet()’ is performed

which is probably not what was intended.

Given the following from the UML Reference Manual

An initial state must have an outgoing completion transition. If there is more than one outgoing transition,
then they must all lack triggers and their guard conditions must partition the possible values.

it is arguable whether the other transition

    / AMS: Create MIDlet()

is legal UML in this context either. It should have a guard.

Assuming this is intended to be the completes normally transition, it can be read as saying

on normal completion the action ‘AMS: Create MIDlet()’ is performed,

which is probably not what was intended either.

2.1.2 The Paused State

Internal Transitions

ID <event-name> <arguments> <guard-conditions> <action-expression>
Paused: 1

AMS: Start

Paused: 2

AMS: Destroy

destroyApp()
Paused: 3

MIDlet: notifyDestroyed()

Paused: 4

MIDlet: resumeRequest()

Later … AMS: Start

Transitions

ID <name> <event-name> <parameter-list> <guard-condition> <action-list> Target State
Paused: 6 AMS: Start Active
Paused: 7 AMS: destroyApp() Destroyed
Paused: 8 AMS: destroyApp() MIDletStateChangeException thrown Destroyed
Paused: 9 AMS: destroyApp() RuntimeException thrown Destroyed
Paused: 10 MIDlet: notifyDestroyed() Destroyed
Paused: 11 MIDlet: resumeRequest() Paused

Problems

Paused: 1

Paused: 1 conflicts with Paused: 6

The ‘AMS: Start’ event results in an internal transition which does nothing, and a transition to the Active state. They cannot both happen.

Paused: 3

Paused: 3 conflicts with Paused: 10.

The ‘MIDlet: notifyDestroyed()’ event results in an internal transition which does nothing, and a transition to the Destroyed state. They cannot both happen.

Paused: 4

Paused: 4 conflicts with Paused: 11

The ‘MIDlet: resumeRequest()’ event results in an internal transition which causes an ‘AMS: Start’ (sic) and a transition back
to the Paused which does nothing. They cannot both happen.

Paused:4 conflicts with the documentation for the method resumeRequest().

Invoking this method MUST have no effect.

Paused: 6

See Paused: 1

Paused:

See Paused: 3

Paused: 11

See Paused: 4

Missing Transitions ?

There is no transition for the ‘MIDlet: notifyPaused()’ event

Possibly this is intentional and denotes that nothing happens, but this is true for other events, but is made explicit, so there
needs to be a consistent approach.

2.1.3 The Active State

Internal Transitions

ID <event-name> <arguments> <guard-conditions> <action-expression>

Active: 1

AMS: Start

startApp()

Active: 2

AMS: startApp()

RuntimeException thrown destroyApp(true)

Active: 3

AMS: Destroy

destroyApp()

Active: 4

MIDlet: notifyDestroyed()

Active: 5

MIDlet: notifyPaused()

startApp()

Active: 6

MIDlet: resumeRequest()

Transitions

ID <name> <event-name> <parameter-list> <guard-condition> <action-list> Target State

Active: 7

AMS: destroyApp()

Destroyed

Active: 8

AMS: destroyApp(true)

MIDletStateChangeException thrown

Destroyed

Active: 9

AMS: destroyApp(true)

RuntimeException thrown

Destroyed

Active: 10

AMS: startApp()

RuntimeException thrown

Active

Active: 11

MIDlet: notifyDestroyed()

Destroyed

Active: 12

MIDlet: notifyPaused()

Active

Active: 13

MIDlet: resumeRequest()

Active

Problems

Active: 1

An ‘AMS: Start’ event results in an internal transition which performs an call to the MIDlet’s startApp() method, although it is unclear what the relationship is between this ‘AMS: Start’ event and the one that resulted in the transition to the Active state.

This behaviour is consistent with the text in Table 15-1: MIDlet states, but they both conflict with the startApp() method documentation whuch states

The method will only be called when the MIDlet is in the Paused state.

although it is arguable that the method documentation itself is either internally inconsistent or very unclear.

Active: 2

Active: 2 conflicts with Active: 10

The completion of an AMS call to the MIDlet’s startApp() method via a RuntimeException results in an internal transition which performs a call to the MIDlet’s destroyApp() method, and in a transition back to the Active state which does nothing. They cannot both happen.

Active: 4

Active: 4 conflicts with Active: 11

The ‘MIDlet: notifyDestroyed()’ events results in an internal transition which does nothing, and a transition to the Destroyed state. They cannot both happen.

Active: 5

Active: 5 conflicts with Active: 12

A ‘MIDlet: notifyPaused()’ event results in an internal transition which performs a call to the MIDlet’s startApp() method, and in a transition back to the Active state which does nothing. They cannot both happen.

Active: 6

Active: 6 conflicts with Active: 13

A ‘MIDlet: resumeRequest()’ event results in an internal transition which does nothing, and in a transition back to the Active state.

One of these is superfluous to requirements.

Active: 10

See Active: 2

Active: 11

See Active: 4

Active: 12

See Active: 5

Active: 13

See Active: 6

Missing Transitions ?

There is no transition for the ‘AMS: startApp()’ event.

Possibly this is intentional and denotes that nothing happens, but this is true for other events, but is made explicit, for example Active: 6. There needs to be a consistent approach.

2.1.4 The Destroyed State

Internal Transitions

ID <event-name> <arguments> <guard-conditions> <action-expression>

Destroyed: 1

MIDlet: resumeRequest()

Transitions

ID <name> <event-name> <parameter-list> <guard-condition> <action-list> Target State

Destroyed: 2

MIDlet: resumeRequest()

Destroyed

Problems

Destroyed: 1

Destroyed: 1 conflicts with Destroyed: 2

A ‘MIDlet: resumeRequest()’ event results in an internal transition which does nothing, and a transition back to the Destroyed state which does nothing.

One of these is superfluous to requirements.

Destroyed: 2

See Destroyed: 1.

Missing Transitions

There is no transition for the ‘MIDlet: notifyDestroyed()’ event, or the ‘MIDlet: notifyPaused()’ event, presumably because nothing happens as a result, but then this is true of the ‘MIDlet: resumeRequest()’ event and it has two transitions !

2.2 Life During Construction ?

The construction of a MIDlet is not part of the MIDlet lifecycle. The first state is entered only after the constructor has completed normally or via an exception, yet in its constructor a MIDlet can call any of the lifecycle methods

  • notifyDestroyed()
  • notifyPaused()
  • resumeRequest()

and some have been known to do just that.

So what should happen ? Possibly nothing, but it would be useful if the specification said so, and it would be easier for it to do so if MIDlet construction was part of the MIDlet lifecycle.

2.3 Backwards Compatibility ?

The current method documentation for notifyPaused() states

Pausing of MIDlets is deprecated. For backward compatibility and to avoid problems with existing MIDlets,
calling notifyPaused in the Active state MUST cause startApp to be called immediately. The MIDlet
is expecting a call to startApp to restore it to the Active state.

The previous method documentation for notifyPaused() ends

If the application pauses itself it will need to call resumeRequest to request to reenter the active state.

So arguably a MIDlet implemented on that basis, having called its notifyPaused() method, would not be

expecting a call to startApp to restore it to the Active state.

at all. In fact it would not be expecting a call to startApp() to occur until after it had made a call to resumeRequest() as per the specification in MIDP 2.

In the circumstances there is probably no right way to ensure backwards compatibility, and there may actually be no legacy MIDlets affected, but it might have been better to say that there is no backwards compatibility in these cases.

3. Revised State Diagram

Below is a revised state diagram. As it is derived from the one in the specification it still suffers from the issues around MIDlet construction as described above, but is hopefully in other respects somewhat clearer than the original.

Events

Event Description
Start Synthetic event to trigger transition to Active state
Shutdown Shutdown of MIDlet requested
DestroyAppCompletes The MIDlet’s destroyApp() method completes, either normally or via an exception.
StartAppCompletes The MIDlet’s startApp() method completes normally
StartAppException The MIDlet’s startApp() method completes by throwing an Exception
NotifyDestroyed MIDlet invokes its notifyDestroyed() method
NotifyPaused MIDlet invokes its notifyPaused() method

Actions

Action Description
DestroyApp The MIDlet’s destroyApp() method is invoked with an argument of true.
StartApp The MIDlet’s startApp() method is invoked.

Guards

Guard Description
ConstructorCompletes True if the MIDlet constructor completes normally
ConstructorException True if the MIDlet constructor throws a RuntimeException

Conventions

If the occurence of an event has no effect when the MIDlet is in that state it is not shown.

The MIDlet Lifecycle


Copyright (c) 2009 By Simon Lewis. All Rights Reserved.

Advertisements

2 Comments »

  1. […] There have been changes to existing javax.microedition.midlet.MIDlet methods to support the new MIDlet lifecycle model, and new methods have been added to support new MIDP 3.0 […]

    Pingback by What’s New In MIDP 3.0 ? Part 11: javax.microedition.midlet.MIDlet « Just An Application — June 16, 2009 @ 2:14 pm

  2. […] What’s New In MIDP 3.0 ? Part 10: The MIDlet Lifecycle […]

    Pingback by “MIDlet not constructed by createMIDlet.” ? « Just An Application — September 11, 2009 @ 11:23 am


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: