![]() ![]() ![]() |
|
![]() |
||||||||||||||||||
![]() |
||||||||||||||||||
![]() |
||||||||||||||||||
![]() |
||||||||||||||||||
![]() |
||||||||||||||||||
![]() |
||||||||||||||||||
![]() |
||||||||||||||||||
![]() |
||||||||||||||||||
|
||||||||||||||||||
Tech Tips archive
J2ME Tech TipsApril 16, 2001WELCOME to the Java Developer ConnectionSM (JDC) JavaTM 2 Platform, Micro Edition (J2METM) Tech Tips, for April 16, 2001. This issue covers: The J2ME Tech Tips are written by Eric Giguere (http://www.ericgiguere.com), an engineer at iAnywhere Solutions, inc, and author of the book "Java 2 Micro Edition: Professional Developer's Guide." USING TIMERSOne of the improvements in version 1.3 of the Java 2 Platform, Standard Edition (J2SE) are classes that make it simpler to schedule tasks for execution by a background thread. The Mobile Information Device Profile (MIDP) also includes these new classes, so Java 2 Platform, Micro Edition (J2ME) developers also benefit.
Tasks are defined and scheduled using two classes:
To define a task, create a subclass of import java.util.*; public class MyTask extends TimerTask { public void run() { System.out.println( "Running the task" ); } }
If the run method looks familiar, it's because
After you define a task, you schedule it by creating an instance
of import java.util.*; Timer timer = new Timer(); TimerTask task = new MyTask(); // wait ten seconds before executing... timer.schedule( task, 10000 ); // wait five seconds before executing, then // execute every ten seconds timer.schedule( task, 5000, 10000 );
There are four versions of the schedule method; each schedules
tasks to occur at a specific time (specified using a
Each After you schedule a task, you can stop its execution by calling its cancel method. This is often done within the run method of the task. Calling the cancel method within the run method guarantees that the current execution of the task is the last one; it also allows the method to be called at any point, even before the task's first scheduled execution. Here's a simple example of a MIDlet that uses a timer to perform a simple simulation of a moving starfield. The stars are drawn as points using low-level graphics APIs. For further discussion about these low-level APIs, see the March 19, 2001 J2ME Tech Tip "Using the MIDP Low-level User Interface API." 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(); } } }
The AN INTRODUCTION TO THE HIGH-LEVEL USER INTERFACE API: ALERTS AND TICKERSThe Mobile Information Device Profile (MIDP) includes both a low-level user interface (UI) API and a high-level UI API. The low-level API gives you complete access to a device's screen and to raw key and pointer events. However, no user interface controls are available with the low-level API -- your application must explicitly draw buttons and other familiar controls. This is the price you pay for the flexibility of the low-level API. The situation is reversed with the high-level API. It provides simple user interface controls, but no direct access to the screen or to raw input events. The controls are fairly abstract to account for the differences in screen size and input methods between various MIDP devices. The MIDP implementation decides how to draw the control and how to manage user input. You can use both low-level and high-level APIs in a single MIDlet, just not at the same time. For example, games that rely on the low-level API to control the screen can also use the high-level API for online help or to display high scores. Business applications that use the high-level API for UI controls can also use the low-level API to draw graphs. For more information about the low-level UI API, see the J2ME Tech Tip for March 19, 2001, "Using the MIDP Low-Level User Interface API." The following tip introduces the high-level UI API, and uses two basic controls to do that: alerts and tickers.
An alert is basically a message dialog, that is, a way of
presenting a single string to the user (along with an optional
image or sound). Alerts display warnings, errors, alarms,
notices, or confirmations. Your application's user interface is
disabled while an alert is displayed. The alert then either
times out automatically (the
You display an alert by creating an instance of the
import javax.microedition.lcdui.*; Image icon = ...; // code omitted Alert msg = new Alert( "Error!" ); msg.setImage( icon ); msg.setString( "No connection was possible." ); msg.setTimeout( 5000 ); // in milliseconds msg.setType( AlertType.ERROR ); You don't need to set all properties. For example, the image is optional, and can be null. (Even if you set the image, the device might not be able to display it.) However, at a minimum, you should always define a title and a message string. As far as other properties:
You can also specify all properties, except for the Alert msg = new Alert( "Error!", "No connection was possible.", icon, AlertType.ERROR ); msg.setTimeout( Alert.FOREVER ); // make it modal
After you've defined the alert, you display it by calling
Display display = ....; // assign on startup Alert msg = ....; // create an alert display.setCurrent( alert, display.getCurrent() );
Notice that the public MyApp extends MIDlet { private Display display; public MyApp(){ display = Display.getDisplay( this ); } public Display getDisplay(){ return display; } // rest of MIDlet goes here }
It's simplest to save the
Note that calling
The sound associated with an alert must be one of five predefined
instances of the
You can play any sound at any time by calling the AlertType.ERROR.playSound( display );
The icon associated with an alert must be an instance of the
Now what about tickers? A ticker is a user interface control that
displays a single line of text, scrolling it onscreen at regular
intervals just like an old-fashioned movie marquee. To use a
ticker, you create an instance of the import javax.microedition.ldcdui.*; Ticker ticker = new Ticker( "Hello, world!" );
To display the ticker, you associate it with a top-level window
created by the high-level UI, that is, any class that extends
the Form f = new Form( "A Title" ); f.setTicker( ticker ); The ticker is displayed in an appropriate area of the window. You can share the same ticker across different windows; the system then attempts to keep it in the same position.
The only thing you can do with a ticker is change its text by
calling the
Here's a simple stock tracking import javax.microedition.midlet.*; import javax.microedition.lcdui.*; import java.util.*; public class StockWatcher extends MIDlet { Display display; Ticker ticker = new Ticker( "" ); Command exitCommand = new Command( "Exit", Command.EXIT, 1 ); Timer timer = new Timer(); StockChecker checker = new StockChecker(); TickerForm form = new TickerForm(); Alert alert = new Alert( "Stock Alert!" ); public StockWatcher() { display = Display.getDisplay( this ); alert.setTimeout( Alert.FOREVER ); } protected void destroyApp( boolean unconditional ) { } protected void startApp() { display.setCurrent( form ); timer.schedule( checker, 0, 30000 ); } protected void pauseApp() { } public void exit(){ timer.cancel(); destroyApp( true ); notifyDestroyed(); } // Display a simple form to hold the ticker class TickerForm extends Form implements CommandListener { public TickerForm(){ super( "Stock Watch" ); setTicker( ticker ); addCommand( exitCommand ); setCommandListener( this ); } public void commandAction( Command c, Displayable d ){ exit(); } } // Check the stock values and put up an alert if // they're beyond certain limits.... class StockChecker extends TimerTask { Random generator = new Random(); int sybsValue = 20000; int sunwValue = 30000; int ibmValue = 40000; StringBuffer buf = new StringBuffer(); public void run(){ String values = getStockValues(); ticker.setString( values ); if( sybsValue < 18000 || sybsValue > 22000 || sunwValue < 28000 || sunwValue > 32000 || ibmValue < 38000 || ibmValue > 42000 ){ alert.setString( values ); } if( !alert.isShown() ){ display.setCurrent( alert, form ); } } private String getStockValues(){ sybsValue = randomStockValue( sybsValue ); sunwValue = randomStockValue( sunwValue ); ibmValue = randomStockValue( ibmValue ); buf.setLength( 0 ); appendValue( "SYBS", sybsValue ); appendValue( "SUNW", sunwValue ); appendValue( "IBM", ibmValue ); return buf.toString(); } // Generate a random stock value... in the // real world you'd use HTTP to obtain the // stock value from a broker's website. private int randomStockValue( int oldVal ){ int incr1 = ( generator.nextInt() % 2 ); int incr2 = ( generator.nextInt() % 16 ); if( incr1 < 1 ){ oldVal -= incr1 * 1000; } else { oldVal += ( incr1 - 2 ) * 1000; } if( incr2 < 8 ){ oldVal -= incr2 * 250; } else { oldVal += incr2 * 250; } return oldVal; } private void appendValue( String stock, int val ){ buf.append( stock ); buf.append( ' ' ); buf.append( Integer.toString( val / 1000 ) ); buf.append( '.' ); buf.append( Integer.toString( val % 1000 ) ); buf.append( ' ' ); } } } Note Sun respects your online time and privacy. The Java Developer Connection mailing lists are used for internal Sun MicrosystemsTM purposes only. You have received this email because you elected to subscribe. To unsubscribe, go to the Subscriptions page, uncheck the appropriate checkbox, and click the Update button. Subscribe To subscribe to a JDC newsletter mailing list, go to the Subscriptions page, choose the newsletters you want to subscribe to, and click Update. Feedback Comments? Send your feedback on the J2ME Tech Tips to: Archives You'll find the J2ME Tech Tips archives at: http://java.sun.com/jdc/J2METechTips/index.html Copyright
Copyright 2001 Sun Microsystems, Inc. All rights reserved. This Document is protected by copyright. For more information, see: http://java.sun.com/jdc/copyright.html - LINKS TO NON-SUN SITES The J2ME Tech Tips may provide, or third parties may provide, links to other Internet sites or resources. Because Sun has no control over such sites and resources, You acknowledge and agree that Sun is not responsible for the availability of such external sites or resources, and does not endorse and is not responsible or liable for any Content, advertising, products, or other materials on or available from such sites or resources. Sun will not be responsible or liable, directly or indirectly, for any damage or loss caused or alleged to be caused by or in connection with use of or reliance on any such Content, goods or services available on or through any such site or resource. J2ME Tech Tips April 16, 2001 Sun, Sun Microsystems, Java, Java Developer Connection, Java Embedded Server, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. |