Further discussion on J2ME progress bar and threading model

Source: Internet
Author: User
Tags abstract exit final implement query sleep stub thread
Author: Favoyang email:favoyang@yahoo.com Welcome to Exchange
Keywords: Threading model J2ME UI Design

Content Summary:
This article is "J2ME progress bar and threading model" a continuation of the article (hereafter referred to as the original, did not read the proposal to see).
This paper discusses the shortcomings of the threading model used in the original text, and puts forward some new methods to improve it. The UI portion of the original text has been flexibly extensible and has not been changed.

Copyright Notice:
This article at the same time published in Www.j2medev.com and my blog (blog.csdn.net/alikeboy), if necessary reprint, there are three ways: 1 contact me and by my consent; 2) and www.j2medev.com have reproduced article cooperation agreement 3 to aggregate my blog via RSS. Reproduced in addition to the need for full text forwarding (including the head of the article), not taken out of context.

Body:

How the foreground UI interacts with background threads
The model in the original text is a foreground progressgaugeui model which is unrelated to the background thread. This design minimizes the complexity of communication and is in fact a single direction model (communicated by Backgroundtask to Pgui). According to the requirements of this model, programmers in the override Backgroundtask Runtask () method, have the obligation to regularly check the operation of the front desk Pgui, and based on this situation to reflect. This mode completely trusts the background thread and gives the background thread the right to respond to the user cancel command, and if the background thread is in trouble and is not responding (such as accessing a very expensive network connection), then the user tries to cancel and the program will temporarily deadlock, Until the background thread has time to check the status of the foreground. And in fact, in the end when to query, how much frequency is the problem. Too much of this type of code in the code snippet can affect the understanding of the normal process.

From the following sequence diagram, you can see this specific process:

We need a method that allows us to force the end task. This method is provided by the background thread itself, named Cancel (). Of course, no one method can force the thread to end immediately (there was a security issue that was canceled). So the Cancel () method tends to force runtask to be interrupted by shutting down resources (a connection, a stream, etc.), and Runtask has the obligation to catch such exceptions and exit immediately based on its own conventions. A picture wins thousand words, let us look at the process of this method.

Obviously, the key is that the foreground thread has a callback to the background thread, which solves the problem. But here's the new problem, which forces us to keep the foreground and background threads tightly coupled (because we need to callback). Can you implement both callbacks and avoid tight coupling of foreground UI and background threads?

Reducing coupling by Cancelable interface
Fortunately, we can use the interface to achieve this.
The previous model was this:

To reduce coupling, we set up an interface
Public interface Cancelable {
/**
* This method is not blocked, should be returned immediately (if necessary to open a new thread)
* In addition, you should avoid repeated calls to this method
*/
public void Cancel ();
}
Next, add support for this method in Progressobserver
Public interface Progressobserver {
......
......
/**
* Set the function object for callback when the task is canceled
* @param Co
*/
public void Setcancelalbeobject (Cancelable co);
}

This allows a callback to Cancelable.cancel () to be made when the user presses the Cancel button. This flexibility has been greatly enhanced.

New Code
The updated code is as follows, in addition to using the above model, the part of the bug has been corrected, where the changes will be in different colors. Detailed usage See comments

/////////////////////////////////////////////////////////////////
Cancelable.java
Package com.favo.ui;

/**
* @author Favo
*
* TODO to change the template of this generated type comment go
* Window-preferences-java-code Style-code Templates
*/
Public interface Cancelable {
/**
* This method is not blocked and should be returned immediately (if necessary to open a new thread)
* In addition, you should avoid repeated calls to this method
*/
public void Cancel ();
}

Progressobserver.java
/*
* Created on 2005-2-26
*
* TODO to change the template of this generated file go
* Window-preferences-java-code Style-code Templates
*/
Package com.favo.ui;

Import Javax.microedition.lcdui.Display;

/**
* @author Favo
*
* This is an observer of a progress bar modelled on Smart ticket, the advantage of which is
* 1, low coupling degree. You can implement this interface through Form,canvas, etc.
* 2, can interrupt the support of the task. is achieved by setting the flag internally and recalling the Cancel () of the cancelobject. A background thread can query this flag to know if a user has interrupted a task.
*/
Public interface Progressobserver {
/**
* The progress bar is reset, mainly to reuse the progress bar
*/
public void Reset ();

/**
* Set the value of the progress bar to the maximum
*/
public void Setmax ();

/**
* Draw yourself on the screen, if the progress bar to open its own thread to automatically update the screen,
* Also constructs and opens painting threads here (often used for animated scroll bars)
*/
public void Show (display display);


/**
* If the progress bar once opened its own thread used to automatically update the screen, (often used to animate the scroll bar), here to close the animation thread
* If not please ignore this method
*/
public void exit ();

/**
* Update progress bar, arbitrary parameters
*/
public void UpdateProgress (Object param1);

/**
* Whether the query progress bar can be paused
*/
public boolean isstoppable ();

/**
* Set whether the progress bar can be paused
* @param stoppable
*/
public void Setstoppable (Boolean stoppable);

/**
* Query whether the user paused the task
* @return
*/
public boolean isstopped ();

/**
* Set Task Pause flag
*/
public void setstopped (Boolean stopped);

/**
* Set Title
*/
public void Settitle (String title);

/**
* Set hints
*/
public void Setprompt (String prompt);

/**
* Sets the function object for callback when task is canceled
* @param Co
*/
public void Setcancelalbeobject (Cancelable co);
}

Progressgaugeui.java
/*
* Created on 2005-2-26
* Window-preferences-java-code Style-code Templates
*/
Package com.favo.ui;

Import Javax.microedition.lcdui.Command;
Import Javax.microedition.lcdui.CommandListener;
Import Javax.microedition.lcdui.Display;
Import javax.microedition.lcdui.Displayable;
Import Javax.microedition.lcdui.Form;
Import Javax.microedition.lcdui.Gauge;

/**
* @author Favo
* The new version of the Pgui, mainly to increase the ability of the cancel task, through the callback Cancelableobject
* Cancel method implementation.
* Preferences-java-code Style-code Templates
*/
public class Progressgaugeui implements Progressobserver, Commandlistener {

private static final int gauge_max = 8;

private static final int gauge_levels = 4;

private static Progressgaugeui Pgui;

Private Form F;

Private gauge gauge;

Private Command Stopcmd;

Boolean stopped;

Boolean stoppable;

int current;

Cancelable Cancelableobject;

Protected Progressgaugeui () {
f = new Form ("");
Gauge = new Gauge ("", False, Gauge_max, 0);
Stopcmd = new Command ("Cancel", Command.stop, 10);
F.append (gauge);
F.setcommandlistener (this);
}

public static Progressgaugeui getinstance () {
if (Pgui = = null) {
return new Progressgaugeui ();
}
return Pgui;
}

/*
* (Non-javadoc)
*
* @see Com.favo.ui.progressobserver#reset (java.lang.Object)
*/
public void Reset () {
current=0;
Gauge.setvalue (0);
Stopped=false;
Setstoppable (FALSE);
Settitle ("");
Setprompt ("");
Cancelableobject=null;
}

/*
* (Non-javadoc)
*
* @see com.favo.ui.progressobserver#updateprogress (java.lang.Object)
*/
public void UpdateProgress (Object param1) {
TODO auto-generated Method Stub
Current= (current+1)%gauge_levels;
Gauge.setvalue (current * gauge_max/gauge_levels);
if (param1!=null && param1 instanceof String) {
Setprompt ((String) param1);
}
}

/*
* (Non-javadoc)
*
* @see com.favo.ui.progressobserver#isstoppable ()
*/
public Boolean isstoppable () {
return stoppable;
}

/*
* (Non-javadoc)
*
* @see com.favo.ui.progressobserver#setstoppable (Boolean)
*/
public void Setstoppable (Boolean stoppable) {
this.stoppable = stoppable;
if (stoppable) {
F.addcommand (Stopcmd);
}else{
F.removecommand (Stopcmd);
}
}

/*
* (Non-javadoc)
*
* @see com.favo.ui.progressobserver#isstopped ()
*/
public Boolean isstopped () {
TODO auto-generated Method Stub
return stopped;
}

/*
* (Non-javadoc)
*
* @see Com.favo.ui.progressobserver#settitle (java.lang.String)
*/
public void Settitle (String title) {
TODO auto-generated Method Stub
F.settitle (title);
}

/*
* (Non-javadoc)
*
* @see com.favo.ui.progressobserver#setprompt (java.lang.String)
*/
public void Setprompt (String prompt) {
Gauge.setlabel (prompt);
}

/*
* (Non-javadoc)
*
* @see javax.microedition.lcdui.commandlistener#commandaction (Javax.microedition.lcdui.Command,
* javax.microedition.lcdui.Displayable)
*/
public void Commandaction (Command arg0, displayable arg1) {
if (arg0==stopcmd) {
if (isstoppable ())
if (!isstopped ()) {//guaranteed to be invoked only once
Setstopped (TRUE);
if (cancelableobject!=null)
Cancelableobject.cancel ();
}
else{
Setprompt ("Can ' t stop!");
}
}
}

/* (Non-javadoc)
* @see Com.favo.ui.progressobserver#show (javax.microedition.lcdui.Display)
*/
public void Show (display display) {
Display.setcurrent (f);
}

/* (Non-javadoc)
* @see Com.favo.ui.progressobserver#exit ()
*/
public void exit () {
Cancelableobject=null;
}

/* (Non-javadoc)
* @see Com.favo.ui.progressobserver#setmax ()
*/
public void Setmax () {
Gauge.setvalue (Gauge_max);
}

/* (Non-javadoc)
* @see com.favo.ui.progressobserver#setstopped (Boolean)
*/
public void setstopped (Boolean stopped) {
this.stopped=stopped;
}

public void Setcancelalbeobject (Cancelable co) {
This.cancelableobject=co;
}

}

Backgroundtask.java
/*
* Created on 2005-2-26
*
* TODO to change the template of this generated file go
* Window-preferences-java-code Style-code Templates
*/
Package com.favo.ui;

Import Javax.microedition.lcdui.AlertType;
Import javax.microedition.lcdui.Displayable;
Import Javax.microedition.lcdui.Display;
Import Javax.microedition.lcdui.Alert;


/**
* @author Favo
*
* TODO to change the template of this generated type comment go to Window-
* Preferences-java-code Style-code Templates
*/
Public abstract class Backgroundtask extends Thread implements cancelable {

Progressobserver Poui;

protected displayable prescreen;

protected Boolean Needalert;

protected Alert Alertscreen;

private display display;

/*
*
*/
Public Backgroundtask (Progressobserver Poui, displayable Pre,
Display display) {
This.poui = Poui;
This.prescreen = pre;
This.display = display;
This.needalert = false;
}

/*
* (Non-javadoc)
*
* @see Java.lang.thread#run ()
*/
public void Run () {
Boolean taskcomplete=false;
try {
Taskcomplete=runtask ();
catch (Exception e) {
Alert Al = New Alert ("Undefine exception", E.getmessage (), NULL,
Alerttype.alarm);
Al.settimeout (Alert.forever);
Display.setcurrent (AL);
finally {
if (!taskcomplete&&poui.isstoppable ()) {
if (poui.isstopped ()) {//If the user interrupts the program
if (Needalert) {
Display.setcurrent (Alertscreen, prescreen);
} else {
Display.setcurrent (Prescreen);
}
}
}
Poui.exit ();
}
}

/**
* Tasks to be defined by the user
* NOTE!!!
* If the task is successfully run, it should be responsible for jumping to the successful screen within this method and returning true.
* If the task fails to run, please set Needalert (whether you need an alert), Alertscreen (alarm screen), prescreen (the previous specific screen to jump back)
* Manually update the progress bar, please call pgui.updateprogress ().
* Make sure that when cancel () is invoked, this method exits immediately and returns False if it is an acceptable behavior to jump out of this function because of an exception.
*/
Public abstract Boolean runtask ();

/**
* This is a lazy way, when you build a good Backgroundtask object, call this method directly, can help you initialize the progress UI, and display. And then start your task thread
*/
public static void Runwithprogressgauge (Backgroundtask btask, String title,
String prompt, Boolean stoppable, display display) {
Progressobserver po = btask.getprogressobserver ();
Po.reset ();
Po.setstoppable (stoppable);
if (stoppable) {
Po.setcancelalbeobject (Btask);
}
Po.settitle (title);
Po.setprompt (prompt);
Po.show (display);
Btask.start ();
}

Public Progressobserver Getprogressobserver () {
return Poui;
}

The Taskcomplete method is canceled because the Runtask already has a return value
//
public void Taskcomplete () {
Getprogressobserver (). setstopped (false);
// }
}


Testprogressgauge.java
/*
* Created on 2005-2-26
*
* TODO to change the template of this generated file go
* Window-preferences-java-code Style-code Templates
*/
Package com.favo.ui;

Import Javax.microedition.lcdui.Alert;
Import Javax.microedition.lcdui.AlertType;
Import Javax.microedition.lcdui.Command;
Import Javax.microedition.lcdui.CommandListener;
Import Javax.microedition.lcdui.Display;
Import javax.microedition.lcdui.Displayable;
Import Javax.microedition.lcdui.Form;
Import Javax.microedition.midlet.MIDlet;
Import javax.microedition.midlet.MIDletStateChangeException;

/**
* @author Favo
*
* TODO to change the template of this generated type comment go to Window-
* Preferences-java-code Style-code Templates
*/
public class Testprogressgauge extends MIDlet implements Commandlistener {

/**
*
*/
Display display;

Command Workcmd;

Command Exitcmd;

Form F;

Public Testprogressgauge () {
Super ();
TODO auto-generated Constructor stub
display = Display.getdisplay (this);
Workcmd = new Command ("Compute", Command.ok, 10);
Exitcmd = new Command ("Exit", Command.exit, 10);
f = new Form ("Test");
F.setcommandlistener (this);
F.addcommand (Workcmd);
F.addcommand (Exitcmd);
}

/*
* (Non-javadoc)
*
* @see Javax.microedition.midlet.midlet#startapp ()
*/
protected void startApp () throws Midletstatechangeexception {
TODO auto-generated Method Stub
Display.setcurrent (f);
}

/*
* (Non-javadoc)
*
* @see Javax.microedition.midlet.midlet#pauseapp ()
*/
protected void Pauseapp () {
TODO auto-generated Method Stub

}

/*
* (Non-javadoc)
*
* @see Javax.microedition.midlet.midlet#destroyapp (Boolean)
*/
protected void Destroyapp (Boolean arg0) throws Midletstatechangeexception {
TODO auto-generated Method Stub

}

/*
* (Non-javadoc)
*
* @see javax.microedition.lcdui.commandlistener#commandaction (Javax.microedition.lcdui.Command,
* javax.microedition.lcdui.Displayable)
*/
public void Commandaction (Command arg0, displayable arg1) {
TODO auto-generated Method Stub
if (arg0 = = Workcmd) {
Progressobserver Poui = Progressgaugeui.getinstance ();
Backgroundtask bktask = new Backgroundtask (Poui, arg1, display) {
public Boolean runtask () {
System.out.println ("Task start!");
Alertscreen = new Alert (
"User Cancel",
"You press the Cancel button and the screen'll jump to the main Form",
NULL, ALERTTYPE.ERROR);
Alertscreen.settimeout (Alert.forever);
Needalert = true;
Do something
Getprogressobserver (). UpdateProgress (null);//Manual update
try {
Thread.Sleep (3000);
catch (Exception e) {
E.printstacktrace ();
return false;
}
Getprogressobserver (). UpdateProgress ("SLEEPD 3s ...");//Manual update
The manual query point is canceled here
if (Getprogressobserver (). isstopped ())
Return
Getprogressobserver (). UpdateProgress (null);//Manual update
Do something again
try {
Thread.Sleep (3000);
catch (Exception e) {
E.printstacktrace ();
return false;
}
Getprogressobserver (). Setmax ()//manual update
Display.setcurrent (New Form ("complete");//Jump Success Screen
return true;
}

public void Cancel () {
This.interrupt ();
}
};
Backgroundtask.runwithprogressgauge (Bktask, "Sleep 6s",
"Sleep now ...", true, display);
}else if (arg0==exitcmd) {
try {
Destroyapp (FALSE);
catch (Midletstatechangeexception e) {
TODO auto-generated Catch block
E.printstacktrace ();
}
Notifydestroyed ();
}
}

}
/////////////////////////////////////////////////////////////////


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.