Java/J2ME/Timer

Материал из Java эксперт
Перейти к: навигация, поиск

A simple class that shows an example of using a Timer and a TimerTask.

   <source lang="java">

/*

* Copyright (c) 2000-2001 Sun Microsystems, Inc. All Rights Reserved.
*/

import java.lang.*; import java.io.*; import java.util.*; import javax.microedition.lcdui.*; import javax.microedition.midlet.*; /**

* A simple class that shows an example of using a Timer and
* a TimerTask.
*
* This MIDlet creates two gauges. One gauge gaugeOne,
* sets elements from low to high. The other, gaugeTwo,
* set elements from high to low. In effect, this has
* gaugeOne "going up", and gaugeTwo "going down."
*
* The two timers fire at different intervals.
*
* There are two commands on our form:
* 
* OK: toggles whether the times are active or not.
* EXIT: exits the MIDlet.
*/

public class TimerMIDlet extends MIDlet implements CommandListener {

   // number of elements in gauge
   final private static int GAUGE_MAX = 10;
   private boolean timersRunning; // tracks state of timers
   private Display myDisplay;     // handle to the display
   private Gauge gaugeOne;        // "going up" gauge
   private Gauge gaugeTwo;        // "going down" gauge
   private Form myScreen;         // form on which to 
                                  // place gauges
   private Command cmdOK;         // OK command
   private Command cmdExit;       // EXIT command
   private Timer timer;
   private MyTimerTask timerTaskOne;
   private MyTimerTask timerTaskTwo;
   /**
    * Internal class that provides a TimerTask.
    */
   private class MyTimerTask extends TimerTask {
       private Gauge myGauge; // reference to gauge
       private boolean goUp;  // if true, go up
       private int num;       // number of times called
       /**
        * Public constructor: stores "direction" and a reference to
        * a gauge.
        */
       public MyTimerTask(Gauge g, boolean up) {
           myGauge = g;
           goUp = up;
       }
       /**
        * As the timer fires, this method is invoked. Set gauge
        * based on goUp
        */
       public void run() {
           num++;
           myGauge.setValue(goUp ?
                            GAUGE_MAX -(num % GAUGE_MAX) :
                            num % GAUGE_MAX);
       }
   }
   /**
    * Public constructor: gets handle to display,
    * creates form, gauges, and commands.
    */
   public TimerMIDlet() {
       myDisplay = Display.getDisplay(this);
       myScreen = new Form("TimerMIDlet");
       gaugeOne = new Gauge("Up Gauge",
                            false,
                            GAUGE_MAX,
                            0);
       myScreen.append(gaugeOne);
       gaugeTwo = new Gauge("Down Gauge",
                            false,
                            GAUGE_MAX,
                            GAUGE_MAX);
       myScreen.append(gaugeTwo);
       cmdOK = new Command("OK", Command.OK, 1);
       cmdExit = new Command("Exit", Command.EXIT, 1);
       myScreen.addCommand(cmdOK);
       myScreen.addCommand(cmdExit);
       myScreen.setCommandListener(this);
   }
   /**
    * Changes the state of timers to/from active to/from
    * not-active.
    */
   private void flipFlop() {
       if (timersRunning) {
           timerTaskOne.cancel();
           timerTaskTwo.cancel();
           timer.cancel();
           timersRunning = false;
       } else {
           timer = new Timer();
           timerTaskOne = new MyTimerTask(gaugeOne, false);
           timerTaskTwo = new MyTimerTask(gaugeTwo, true);
           timer.schedule(timerTaskOne, 0, 1000);
           timer.schedule(timerTaskTwo, 0, 1500);
           timersRunning = true;
       }
   }
   /**
    * Called by the system to start our MIDlet.
   * @exception MIDletStateChangeException
    */
   protected void startApp() throws MIDletStateChangeException {
       myDisplay.setCurrent(myScreen);
       flipFlop();
   }
   /**
    * Called by the system to pause our MIDlet.
    * No actions required by our MIDLet.
    */
   protected void pauseApp() {}
   /**
    * Called by the system to end our MIDlet.
    * No actions required by our MIDLet.
    */
   protected void destroyApp(boolean unconditional) {}
   /***
    * Respond to command selections. Process two commands:
    * 
    * OK: flip flop the timers to/from active
    * EXIT: exit this MIDlet
    * 
    */
   public void commandAction(Command c, Displayable d) {
       if (c == cmdOK) {
           flipFlop();
       } else if (c == cmdExit) {
           destroyApp(false);
           notifyDestroyed();
       }
   }

}


      </source>
   
  
 
  



Demonstrate simple animation using a Timer and TimerTask

   <source lang="java">

/*--------------------------------------------------

  • Animation.java
  • Demonstrate simple animation using
  • a Timer and TimerTask
  • Example from the book: Core J2ME Technology
  • Copyright John W. Muchow http://www.CoreJ2ME.ru
  • You may use/modify for any non-commercial purpose
  • -------------------------------------------------*/

import java.util.*; import javax.microedition.midlet.*; import javax.microedition.lcdui.*; public class Animation extends MIDlet {

 private Display  display;       // The display
 private AnimationCanvas canvas; // Canvas 
 private Timer tm;               // Timer
 private AnimateTimerTask tt;    // Task

 public Animation()
 {
   display = Display.getDisplay(this);
   canvas  = new AnimationCanvas(this);
   // Create task that fires off every 1/10 second    
   tm = new Timer();
   tt = new AnimateTimerTask(canvas);
   tm.schedule(tt, 0, 100);    
 }

 protected void startApp()
 {
   display.setCurrent(canvas);
 }

 protected void pauseApp()
 { }
 protected void destroyApp(boolean unconditional)
 { }

 public void exitMIDlet()
 {
   destroyApp(true);
   notifyDestroyed();
 }

}

/*--------------------------------------------------

  • AnimateTimerTask.java
  • Change location of bouncing ball on the canvas
  • Example from the book: Core J2ME Technology
  • Copyright John W. Muchow http://www.CoreJ2ME.ru
  • You may use/modify for any non-commercial purpose
  • -------------------------------------------------*/

class AnimateTimerTask extends TimerTask {

 private AnimationCanvas canvas;
 
 public AnimateTimerTask(AnimationCanvas canvas)
 {
   this.canvas = canvas;
 }
 /*--------------------------------------------------
 * Determine next location of the ball.
 * If the ball reaches any edge, change the color
 * Track how many times we"ve switced directions
 *-------------------------------------------------*/  
 public final void run()
 {
   // If past the right edge or prior to left edge...
   if ((canvas.x_loc + canvas.radius +  canvas.x_dir > canvas.getWidth()) ||
       (canvas.x_loc - canvas.radius +  canvas.x_dir < 0))
   {                
     canvas.x_dir = -canvas.x_dir;
     canvas.changeColor();
     canvas.directionChanged++;
   }
   // If past the bottom or before the top...
   if ((canvas.y_loc + canvas.radius +  canvas.y_dir > canvas.getHeight()) ||
       (canvas.y_loc - canvas.radius + canvas.y_dir < 0))      
   {          
     canvas.y_dir = -canvas.y_dir;
     canvas.changeColor();
     canvas.directionChanged++;      
   }
   // Update the new x and y locations
   canvas.x_loc += canvas.x_dir;
   canvas.y_loc += canvas.y_dir;

   canvas.repaint();            
 }

} /*--------------------------------------------------

  • AnimationCanvas.java
  • Show a ball that bounces around on a canvas
  • Each time we hit a wall we change the ball color
  • We also clear the screen after "n" number of
  • hits against the wall
  • The "left" and "right" keys change the ball size
  • The "Fire" key resets the display, however,
  • it leaves the ball size the same.
  • Example from the book: Core J2ME Technology
  • Copyright John W. Muchow http://www.CoreJ2ME.ru
  • You may use/modify for any non-commercial purpose
  • -------------------------------------------------*/

class AnimationCanvas extends Canvas implements CommandListener {

 private Animation midlet;         // Main midlet
 private Command cmExit;          // Exit midlet
 private int    keyFire,           // Reset ball            
                keyRight,          // Increase ball radius
                keyLeft;           // Decrease ball radius
 private boolean clearBackground = false; // Clear background
 private Random random;            // Random number
 int x_loc,                        // Current x & y locations
     y_loc,                        
     radius,                       // Ball radius
     red,                          // rgb colors
     green,                       
     blue,                       
     x_dir,                // Next x & y positions of ball
     y_dir,                
     start_x,              // Where ball starts 
     start_y,
     directionChanged = 0; // How many times we"ve hit a wall
 private static final int MAX_CHANGES = 50;
 /*--------------------------------------------------
 * Constructor
 *-------------------------------------------------*/
 public AnimationCanvas(Animation midlet)
 {
   // Save reference to main midlet
   this.midlet = midlet;
   random = new java.util.Random();
   
   // Determine starting location and direction of ball
   init();
   radius = 7;
   
   // Create exit command and "Fire" key
   cmExit = new Command("Exit", Command.EXIT, 1);
   keyFire =  getKeyCode(FIRE);
   keyRight = getKeyCode(RIGHT);
   keyLeft = getKeyCode(LEFT);
   
   addCommand(cmExit);
   setCommandListener(this);
 } 
 /*--------------------------------------------------
 * Paint a new ball, clearing the screen as asked
 *-------------------------------------------------*/
 protected void paint(Graphics g)
 {
   // Max edge hits, reset everything
   if (directionChanged > MAX_CHANGES)
     init();
   
   // Clear the background
   if (clearBackground)
   {
     g.setColor(255, 255, 255);
     g.fillRect(0, 0, getWidth(), getHeight());
     clearBackground = !clearBackground;
   }
   
   // Set color and draw another ball
   g.setColor(red, green, blue);                    
   g.fillArc( x_loc, y_loc, radius, radius, 0, 360);
 }
 /*--------------------------------------------------
 * Initialize starting location and direction of ball
 *-------------------------------------------------*/
 private void init()
 {
   // Start close to the middle
   x_loc = getWidth() / 2;
   y_loc = getHeight() / 2;      
   // The direction the ball is heading
   x_dir = (random.nextInt() % 10);
   if (x_dir == 0)  x_dir = 1;
   
   y_dir = (random.nextInt() % 10);
   if (y_dir == 0)  y_dir = 1;
   directionChanged = 0;    
   clearBackground = true;      
   changeColor();      
 }
 
 /*--------------------------------------------------
 * Change the colors.
 * I am counting on the implemention to substitute
 * a use-able color if any of these are out of the 
 * devices supported range
 *-------------------------------------------------*/
 protected void changeColor()
 {
   // The shift is to remove any sign (negative) bit    
   red = (random.nextInt() >>> 1) % 256;
   green = (random.nextInt() >>> 1) % 256;
   blue = (random.nextInt() >>> 1) % 256;
 }
 /*--------------------------------------------------
 * Event handling
 *-------------------------------------------------*/  
 public void commandAction(Command c, Displayable d)
 {
   if (c == cmExit)
     midlet.exitMIDlet();
 }
 /*--------------------------------------------------
 * Reset ball is "Fire" key is pressed
 *-------------------------------------------------*/  
 protected void keyPressed(int keyCode)
 {
   // Restart
   if (keyCode == keyFire)
     init();
   // Decrease ball size
   else if (keyCode == keyLeft)
     radius = Math.max(1, --radius);
   else if (keyCode == keyRight)
   // Increase ball size
    radius = Math.min(getWidth() / 4, ++radius);
 }

}


      </source>
   
  
 
  



Timer and animation

   <source lang="java">

/* License

* 
* Copyright 1994-2004 Sun Microsystems, Inc. All Rights Reserved.
* 
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*  
*  * Redistribution of source code must retain the above copyright notice,
*      this list of conditions and the following disclaimer.
* 
*  * Redistribution in binary form must reproduce the above copyright notice,
*      this list of conditions and the following disclaimer in the
*      documentation and/or other materials provided with the distribution.
* 
* Neither the name of Sun Microsystems, Inc. or the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*  
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*  
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility. 
*/

import javax.microedition.midlet.*; import javax.microedition.lcdui.*; import java.util.*; public class TimerDemo extends MIDlet {

 Display    display;
 StarField  field = new StarField();
 FieldMover mover = new FieldMover();
 Timer      timer = new Timer();
 public TimerDemo() {
   display = Display.getDisplay( this );
 }
 protected void destroyApp( boolean unconditional ) { }
 protected void startApp() {
   display.setCurrent( field );
   timer.schedule( mover, 100, 100 );
 }
 protected void pauseApp() { }
 public void exit(){
   timer.cancel(); // stop scrolling
   destroyApp( true );
   notifyDestroyed();
 }

class FieldMover extends TimerTask {

 public void run(){
   field.scroll();
 }

} class StarField extends Canvas {

 int        height;
 int        width;
 int[]      stars;
 Random     generator = new Random();
 boolean    painting = false;
 public StarField(){
   height      = getHeight();
   width       = getWidth();
   stars       = new int[ height ];
   for( int i = 0; i < height; ++i ){
     stars[i] = -1;
   }
 }
 public void scroll() {
   if( painting ) return;
   for( int i = height-1; i > 0; --i ){
     stars[i] = stars[i-1];
   }
   stars[0] = ( generator.nextInt() % ( 3 * width ) ) / 2;
   if( stars[0] >= width ){
     stars[0] = -1;
   }
   repaint();
 }
 protected void paint( Graphics g ){
   painting = true;
   g.setColor( 0, 0, 0 );
   g.fillRect( 0, 0, width, height );
   g.setColor( 255, 255, 255 );
   for( int y = 0; y < height; ++y ){
     int x = stars[y];
     if( x == -1 ) continue;
     g.drawLine( x, y, x, y );
   }
   painting = false;
 }
 protected void keyPressed( int keyCode ){
   exit();
 }

} }


      </source>
   
  
 
  



Timer and sticker

   <source lang="java">

/*

* TimerMIDlet.java Copyright (c) 2000 Sun Microsystems, Inc. All Rights
* Reserved.
* 
* Author: Srikanth Raju
* 
* This software is the confidential and proprietary information of Sun
* Microsystems, Inc. ("Confidential Information"). You shall not disclose such
* Confidential Information and shall use it only in accordance with the terms
* of the license agreement you entered into with Sun.
* 
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
* SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
* NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
* LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES.
*/

import java.util.Timer; import java.util.TimerTask; import javax.microedition.lcdui.Choice; import javax.microedition.lcdui.ChoiceGroup; import javax.microedition.lcdui.rumand; import javax.microedition.lcdui.rumandListener; import javax.microedition.lcdui.Display; import javax.microedition.lcdui.Displayable; import javax.microedition.lcdui.Form; import javax.microedition.lcdui.List; import javax.microedition.lcdui.Ticker; import javax.microedition.midlet.MIDlet; import javax.microedition.midlet.MIDletStateChangeException; public class TimerMIDlet extends MIDlet implements CommandListener {

 private Display display = null;
 private Ticker stockTicker = null;
 private String[] _stocks = { "SUNW", "ORCL", "NOK", "MOT" };
 private String[] _prices = { "9", "11", "9.25", "14.5" };
 private static final Command exitCommand = new Command("Exit",
     Command.STOP, 0);
 private static final Command backCommand = new Command("Back",
     Command.BACK, 0);
 private static final Command doneCommand = new Command("Done", Command.OK,
     0);
 private Timer stockRefresh = null;
 private StockRefreshTask stockRefreshTask = null;
 private int refresh_interval = 10000; // 1000 = 1 second
 private List menu = null;
 private ChoiceGroup _updatesChoices = null;
 private Form _updatesForm = null;
 private String _currentMenu = null;
 public TimerMIDlet() {
 }
 public void startApp() throws MIDletStateChangeException {
   display = Display.getDisplay(this);
   menu = new List("Stock Menu", Choice.IMPLICIT);
   menu.append("Updates", null);
   menu.append("Add Stocks", null);
   menu.append("Remove Stocks", null);
   menu.addCommand(exitCommand);
   menu.setCommandListener(this);
   // Make the ticker
   stockTicker = new Ticker(makeTickerString());
   menu.setTicker(stockTicker);
   display.setCurrent(menu);
   _currentMenu = "Stock Menu";
   _updatesForm = new Form("Updates");
   _updatesChoices = new ChoiceGroup("Update Interval:", Choice.EXCLUSIVE);
   _updatesChoices.append("Continuous", null); // will be 10 seconds
   _updatesChoices.append("15 minutes", null);
   _updatesChoices.append("30 minutes", null);
   _updatesChoices.append("1 hour", null);
   _updatesChoices.append("3 hours", null);
   _updatesForm.setTicker(stockTicker);
   _updatesForm.append(_updatesChoices);
   _updatesForm.addCommand(backCommand);
   _updatesForm.addCommand(doneCommand);
   _updatesForm.setCommandListener(this);
   //Set up and start the timer to refresh the stock quotes
   stockRefreshTask = new StockRefreshTask();
   stockRefresh = new Timer();
   stockRefresh.schedule(stockRefreshTask, 0, refresh_interval);
 }
 public String makeTickerString() {
   String retString = new String();
   for (int i = 0; i < _stocks.length; i++) {
     retString += _stocks[i];
     retString += " @ ";
     retString += _prices[i];
     retString += " ";
   }
   return retString;
 }
 public void pauseApp() {
   // free memory used by these objects
   display = null;
   stockRefresh = null;
   stockRefreshTask = null;
 }
 public void destroyApp(boolean unconditional)
     throws MIDletStateChangeException {
   notifyDestroyed();
 }
 public void commandAction(Command c, Displayable d) {
   if (c == exitCommand) {
     try {
       destroyApp(false);
     } catch (MIDletStateChangeException msce) {
       System.out.println("Error in detroyApp(false) ");
       msce.printStackTrace();
     }
     notifyDestroyed();
   } else if (c == backCommand) {
     _currentMenu = "Stock Menu";
     display.setCurrent(menu);
   } else if (c == doneCommand) {
     switch (_updatesChoices.getSelectedIndex()) {
     case 0:
       refresh_interval = 10000;
       break;
     case 1:
       refresh_interval = 900000;
       break;
     case 2:
       refresh_interval = 1800000;
       break;
     case 3:
       refresh_interval = 3600000;
       break;
     case 4:
       refresh_interval = 10800000;
       break;
     default:
       break;
     }
     stockRefreshTask.cancel();
     stockRefreshTask = new StockRefreshTask();
     stockRefresh.schedule(stockRefreshTask, 0, refresh_interval);
     display.setCurrent(menu);
     _currentMenu = "Stock Menu";
   } else {
     List shown = (List) display.getCurrent();
     switch (shown.getSelectedIndex()) {
     case 0: // Updates
       display.setCurrent(_updatesForm);
       _currentMenu = "Updates";
       break;
     case 1: // Add Stock
       System.out.println("Add Stock... ");
       _currentMenu = "Add Stock";
       break;
     case 2: // Remove Stock
       System.out.println("Remove Stock... ");
       _currentMenu = "Remove Stock";
       break;
     }
   }
 }
 /**
  * This is an extention of the TimerTask class which runs when called by
  * Timer. It refreshes the stock info for each stock from the quote server
  * and checks to see if any of the alerts should be fired.
  */
 class StockRefreshTask extends TimerTask {
   /**
    * Execute the Timer"s Task
    */
   public void run() {
     try {
       // Just return if the database is empty
       if (_stocks.length == 0)
         return;
       else {
         for (int i = 0; i < _stocks.length; i++) {
           System.out.println("Stock price for symbol: "
               + _stocks[i] + " is: " + _prices[i]);
         }
       }
     } catch (Exception e) {
       System.out.println("error("UPDATE FAILED", 2000)");
     }
   }
 }

}

      </source>
   
  
 
  



Timer Template

   <source lang="java">

/*--------------------------------------------------

  • TimerTemplate.java
  • Test all six Timer scheduling options
  • Example from the book: Core J2ME Technology
  • Copyright John W. Muchow http://www.CoreJ2ME.ru
  • You may use/modify for any non-commercial purpose
  • -------------------------------------------------*/

import java.util.*; import javax.microedition.midlet.*; import javax.microedition.lcdui.*; public class TimerTemplate extends MIDlet implements CommandListener {

 private Display display;      // Our display
 private Form fmMain;         // Main form
 private Command cmExit;      // Exit midlet
 private Command cmStop;      // Stop the timer
 private Timer tm;          // Timer
 private TestTimerTask tt;       // Task
 private int count = 0;        // How many times has task run
 public TimerTemplate()
 {
   display = Display.getDisplay(this);
   // Create main form
   fmMain = new Form("Timer Test");
   fmMain.append("waiting...\n");
   // Create commands and add to form
   cmExit = new Command("Exit", Command.EXIT, 1);
   cmStop= new Command("Stop", Command.STOP, 2);
   fmMain.addCommand(cmExit);
   fmMain.addCommand(cmStop);
   fmMain.setCommandListener(this);
   
   //------------------------------------------------------
   // Option #1 - One time task with delayed start
   // Create a timer that will go off in 5 seconds
   //------------------------------------------------------
   tm = new Timer();
   tt = new TestTimerTask();
   tm.schedule(tt,5000);    
   //------------------------------------------------------
   // Option #2 - Fixed-delay repeating task with delayed start
   // Create a timer that will go off in 5 seconds
   // Repeating every 3 seconds
   //------------------------------------------------------

// tm = new Timer(); // tt = new TestTimerTask(); // tm.schedule(tt,5000, 3000);

   //------------------------------------------------------
   // Option #3 - Fixed-rate repeating task with delayed start
   // Create a timer that will go off in 5 seconds
   // Repeating every 3 seconds
   //------------------------------------------------------

// timer = new Timer(); // tt = new TestTimerTask(); // timer.scheduleAtFixedRate(tt,5000, 3000);

   //------------------------------------------------------
   // Option #4 - One time task at specified date
   // Create timer that starts at current date
   //------------------------------------------------------

// timer = new Timer(); // tt = new TestTimerTask(); // timer.schedule(tt, new Date());

   //------------------------------------------------------
   // Option #5 - Fixed-delay repeating task starting 
   //             at a specified date
   // Create timer that starts at current date
   // Repeating every 3 seconds
   //------------------------------------------------------

// timer = new Timer(); // tt = new TestTimerTask(); // timer.schedule(tt, new Date(), 3000);

   //------------------------------------------------------
   // Option #6 - Fixed-rate repeating task starting
   //             at a specified date
   // Create timer that starts at current date
   // Repeating every 3 seconds
   //------------------------------------------------------

// timer = new Timer(); // tt = new TestTimerTask(); // timer.scheduleAtFixedRate(tt, new Date(), 3000);

 }
 /*--------------------------------------------------
 * Show the main Form
 *-------------------------------------------------*/
 public void startApp ()
 {
   display.setCurrent(fmMain);
 }
 /*--------------------------------------------------
 * Shutting down. Cleanup all we created
 *-------------------------------------------------*/
 public void destroyApp (boolean unconditional)
 {
 }
 /*--------------------------------------------------
 * No pause code necessary
 *-------------------------------------------------*/
 public void pauseApp ()
 { }
 /*--------------------------------------------------
 * Process events for the main form
 *-------------------------------------------------*/
 public void commandAction(Command c, Displayable d)
 {
   if (c == cmStop)
   {
     tm.cancel();
   }
   else if (c == cmExit)
   {
     destroyApp(false);
     notifyDestroyed();
   }
 }
 /*--------------------------------------------------
 * TestTimerTask Class - Run the task
 *-------------------------------------------------*/  
 private class TestTimerTask extends TimerTask
 {
   public final void run()
   {
     fmMain.append("run count: " + ++count + "\n");
   }
 }

}


      </source>