Aegidius
 Plüss   Aplulogo
     
 www.aplu.ch      Print Text 
© 2021, V10.4
 
  Gidlet
 
   


Nineteenth example

Purpose: There are three mechanism to store data persistently in JavaME: Packed as file resource in the application JAR, files in the device file system and using the RMS (Record Managing System). Each of them as advantages and disadvantages. When using JAR resources, the data may only be read but not modified, using the file system requires an API that is not supported by all actual devices and special access rights or MIDlet signing. The RMS is well suited to store information that must survive from one MIDlet execution to another.

Gidlet's wrapper class StringStore simplifies the use of the RMS, because no stream operations are needed. Strings may be appended to the store and retrieved in the order they are added to the store. Similar to MStore, the write and append operation create the store automatically if it does not yet exist. The read operation retrieves the whole store, even if several strings have been appended one by one.

In the following example two lines are appended to a string store. Then the store is read and the content displayed. If run several times, more and more lines are appended.

// StoreAppendGidlet.java

import
 ch.aplu.gidlet.*;

public
 class StoreAppendGidlet extends Gidlet
{
  
public void main()
  
{
    MConsole c 
= new MConsole();
    StringStore store 
= new StringStore("foo");
    c.
println("Appending two lines...");
    store.
append("line1\n");
    store.
append("line2\n");

    c.
println("Reading store...");
    
String content = store.read();
    c.
println(content);
  
}
}

Execute StoreAppendGidlet (if you have the Sun's Wireless Toolkit (WTK) installed and the JAD extension registered. Learn how to register the JAD extension). If you execute the gidlet with this link, the store is removed when the emulator closes.

Discussion: The first time the gidlet is run, the store named foo is created. To delete it, StringStore's delete() method must be called.

 

Twentieth example

Purpose: When write() is used instead of append(), all previous data in the store are discarded.

// StoreWriteGidlet.java

import ch.aplu.gidlet.*;

public class StoreWriteGidlet extends Gidlet
{
  public void main()
  {
    MConsole c = new MConsole();
    StringStore store = new StringStore("foo");
    c.println("Appending two lines...");
    StringBuffer sb = new StringBuffer();
    sb.append("line1\n");
    sb.append("line2\n");
    store.write(sb.toString());

    c.println("Reading store...");
    String content = store.read();
    c.println(content);
  }
}

Execute StoreWriteGidlet (if you have the Sun's Wireless Toolkit (WTK) installed and the JAD extension registered. Learn how to register the JAD extension).

Discussion: Each time the gidlet is run, the content of the string buffer is written into the store. (Do not mistake StringBuffer's append() for StringStore's append() method.)

 

Twenty-first example

Purpose: In a typical application the content of an edit window is automatically saved when the application exits and reloaded the next time it is run.

// EditGidlet.java

import ch.aplu.gidlet.*;

public class EditGidlet extends Gidlet
{
  private StringStore store = new StringStore("doc");
  private MTextBox tb = new MTextBox("Enter text");

  public void main()
  {
    String s = store.read();
    if (!= null) // Record store must exist
      tb.setText(s);
    tb.show();
  }

  public void doExit()
  {
    store.write(tb.getText());
    notifyDestroyed();
  }
}

Execute EditGidlet (if you have the Sun's Wireless Toolkit (WTK) installed and the JAD extension registered. Learn how to register the JAD extension). If you execute the gidlet with this link, the store is removed when the emulator closes.

Discussion: Instead of calling exists() to check whether the string store has been created before, just read it and check for the null string.

 

Twenty-second example

Purpose: The StringStore is useful to save information from one program invocation to another, e.g. setup/option parameters or the program state to resume execution at the same point.

In the following example we save the score of a reaction time test, so that the user can train himself to become better and better (or find out what mood is responsible to do it worse).

When the program starts, a form is displayed where the date/time and the score of the last execution is shown. This information is extracted from a StringStore. The reaction time test is performed by showing a green circle for a random time between 2 and 5 seconds, then the circle suddenly changes to red (like a traffic light). A timer is started and the user must press the fire button (normally in the middle of the cursor keys) as quick as possible. When the key is hit, the timer is stopped and its value considered to be the reaction time. This process is repeated 5 times. The test score is the mean value of the 5 reaction times. It is displayed and saved along with the current date/tune in the StringStore.

// ReactionGidlet.java

import javax.microedition.lcdui.*;
import java.util.*;
import ch.aplu.gidlet.*;

public class ReactionGidlet extends Gidlet
{
  private MPanel p;

  public void main()
  {
    String[] result =  new String[2];
    StringStore store = new StringStore("StateStore");
    String entry = store.read();

    if (entry == null// Never played before
    {
      result[0] = "(never played)";
      result[1] = "?";
    }
    else
      result = split(entry, ";");

    MForm f = new MForm("Reaction Time");
    StringItem si = f.addOutputField();
    String info =  "Last test on\n" + result[0] +
                   "\n\nLast average score:\n" +
                   result[1] + " ms" +
                   "\n\nOK to start";
    si.setText(info);
    f.show();
    waitOk(true);
    p = new MPanel("When RED press FIRE");

    long average = play();  // Blocks until finished

    info = "Last average score:\n" + result[1] +
           " ms\n\nNew average score:\n" +
           Long.toString(average) + " ms";
    si.setText(info);
    f.removeOkButton();
    f.show();
    Date today = new Date();
    store.write(today + ";" + Long.toString(average));
  }

  private long play()
  {
    long score;
    long average = 0;
    p.addKeyListener(this);
    p.removeExitButton();
    p.move(0.5, 0.7);
    p.show();
    Random r = new Random();
    int nb = 5;
    for (int i = 0; i < nb; i++)
    {
      p.color(GREEN);
      p.fillCircle(0.1);
      startTimer();
      int delay = r.nextInt(3000) + 2000;
      while (getTime() < delay);  // Random wait
      p.color(RED);
      p.fillCircle(0.1);
      startTimer();
      putSleep();
      score = getTime();
      p.color(BLACK);
      p.label((i + 1)  + ". score: " +
       Long.toString(score) + " ms", 0.5 - 0.07*i);
      average += score;
    }
    p.label("OK to recapitulate", 0.5 - 0.07*nb);
    waitOk(true);
    return average / 5;
  }

  public void keyPressed(int keyCode)
  {
    if (p.getGameAction(keyCode) == Canvas.FIRE)
      wakeUp();
  }
}

Execute ReactionGidlet (if you have the Sun's Wireless Toolkit (WTK) installed and the JAD extension registered. Learn how to register the JAD extension). If you execute the gidlet with this link, the store is removed when the emulator closes.

Discussion: We save the score and date/time as semicolon-separated parts of a string. It is convenient to use split() to separate each part when reading the string back from the store. putSleep() halts the thread at the beginning of the test phase. When the user clicks the fire button, wakup() in the callback method keyPressed() resumes the waiting thread.