欢迎光临
我们一直在努力

再议j2me进度条与线程化模型-JSP教程,J2ME开发

建站超值云服务器,限时71元/月

作者:favoyang email:favoyang@yahoo.com 欢迎交流

keywords:线程化模型 j2me ui设计

内容提要:

本文是《j2me进度条与线程化模型》一文的续(以后简称原文,没看过的建议看一下)。

讨论了原文中使用的线程模型的不足,并针对她的缺点提出了新的改进办法并给出了改进后的实现。因原文中ui部分有灵活的扩展性,未作更改。

版权声明:

本文同时发表在www.j2medev.com和我的blog(blog.csdn.net/alikeboy)上,如果需要转载,有三个途径:1)联系我并经我同意;2)和www.j2medev.com有转载文章合作协议的 3)通过rss聚合我的blog。另外转载需要全文转发(包括文章的头部),不要断章取义。

正文:

前台ui如何和后台线程交互

原文中模型,是一个前台的progressgaugeui与后台线程无关的模型。这样设计的时候最大程度上的化简了通信的复杂性,实际上是一种单方向的模型(由backgroundtask 向 pgui通信)。按照这种模式的要求,程序员在override backgroundtask 的runtask()方法时,有义务定期的去查训前台的pgui的运行情况,并根据这种情况做出反映。这样这种模式完全相信后台线程,将是否响应用户cancel命令的权利交给了后台线程,如果后台线程陷入麻烦没有响应了(比如访问一个很昂贵的网络连接),此时用户试图cancel也没有用,程序将会暂时的死锁,直到后台线程有时间去检查前台的状态。并且在实际情况中,到底什么时候去查询,多大的频率都是问题。在代码段中过多的此类代码,会影响对正常的流程的理解。

从下面的这个顺序图,可以看到这个具体流程:

我们需要一个方法,让我们能够强制的结束task。这个方法由背景线程自己提供,取名叫做cancel()。当然没有任何一个方法可以强迫线程立即结束(曾经有,因为安全性问题而被取消)。所以cancel()方法往往通过关闭的资源(一个连接,一个流等)来迫使runtask发生异常被中断,runtask有义务根据自己的约定捕捉此类异常并立即退出。一图胜千言,让我们看看这种方法的流程。

很显然的,关键在于前台的线程对后台的线程进行了回调,这样就可以解决问题了。但是新的问题来了,这样做迫使我们将前台与后台线程紧密的耦合在了一起(因为要回调嘛)。能不能既实现回调又避免前台ui与后台线程的紧密耦合呢?

通过cancelable接口降低耦合度

幸好,我门可以利用接口来实现这一点。

先前的模型是这样的:

为了降低耦合,我们建立一个接口

public interface cancelable {

/**

* 本方法非阻塞,应该立即返回(如有必要开启新的线程)

* 此外应避免对此方法的重复调用

*/

public void cancel();

}

接下来在progressobserver加入对这个方法的支持

public interface progressobserver {

……

……

/**

* 设置取消task时回调的函数对象

* @param co

*/

public void setcancelalbeobject(cancelable co);

}

这样,就可以在用户按下取消按钮的时候,就可以进行对cancelable.cancel()的回调。这样灵活性大大增强了。

新代码

更新后的代码如下,除了改用以上的模型外,还对部分的bug进行了更正,更改的地方会用不同的颜色表示。详细的用法可参见注释

/////////////////////////////////////////////////////////////////

cancelable.java

package com.favo.ui;

/**

* @author favo

*

* todo to change the template for this generated type comment go to

* window – preferences – java – code style – code templates

*/

public interface cancelable {

/**

* 此方法非阻塞,应该立即返回(如果有必要开启新的线程)

* 此外应避免对此方法的重复调用

*/

public void cancel();

}

progressobserver.java

/*

* created on 2005-2-26

*

* todo to change the template for this generated file go to

* window – preferences – java – code style – code templates

*/

package com.favo.ui;

import javax.microedition.lcdui.display;

/**

* @author favo

*

* 这是仿照smart ticket制作的进度条观察者,这个模型的优点是

* 1,低耦合度。你可以通过form,canvas等来实现这个接口

* 2,可中断任务的支持。是通过在内部设置flag并回调cancelobject的cancel()来实现的。后台线程可以通过查询这个flag从而知道用户是否中断过task。

*/

public interface progressobserver {

/**

* 将进度条复位,主要为了重复利用进度条

*/

public void reset();

/**

* 将进度条的值为设置最大

*/

public void setmax();

/**

* 将自己绘制在屏幕上,如果进度条要开启自身的线程用于自动更新画面,

* 也在这里构造并开启绘画线程(常用于动画滚动条)

*/

public void show(display display);

/**

* 如果进度条曾经开启自身的线程用于自动更新画面,(常用于动画滚动条),在这里关闭动画线程

* 如果没有请忽略此方法

*/

public void exit();

/**

* 更新进度条,参数任意

*/

public void updateprogress(object param1);

/**

* 查询进度条是否可以暂停

*/

public boolean isstoppable();

/**

* 设置进度条是否可以暂停

* @param stoppable

*/

public void setstoppable(boolean stoppable);

/**

* 查询用户是否暂停了任务

* @return

*/

public boolean isstopped();

/**

* 设置任务暂停标记

*/

public void setstopped(boolean stopped);

/**

* 设置标题

*/

public void settitle(string title);

/**

* 设置提示

*/

public void setprompt(string prompt);

/**

* 设置是否取消task时回调的函数对象

* @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

* 新版本的pgui,主要是增加了cancel task的能力,通过回调cancelableobject的

* cancel方法实现。

* 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()){//保证仅被调用一次

setstopped(true);

if(cancelableobject!=null)

cancelableobject.cancel();

}

else{

setprompt("cant 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 for this generated file go to

* 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 for 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 (needalert) {

display.setcurrent(alertscreen, prescreen);

} else {

display.setcurrent(prescreen);

}

}

}

poui.exit();

}

}

/**

* 须由用户定义的任务

* 注意!!!

* 任务如果成功的运行,应该由此方法内部负责跳转至成功画面,并返回true.

* 若任务运行失败,请设置needalert(是否需要警报),alertscreen(警报画面),prescreen(跳转回的前一个具体屏幕)

* 手动更新进度栏,请调用pgui.updateprogress().

* 请确保当cancel()调用时,此方法会立即退出,并返回false(如果因为异常跳出此函数是可以接受的行为).

*/

public abstract boolean runtask();

/**

* 这是一个偷懒的办法,当你构造好backgroundtask对象后,直接调用这个方法, 可以帮助你初始化进度ui,并显示出来。之后启动你的任务线程

*/

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;

}

//取消了taskcomplete方法,因为runtask已经有了返回值

//

// public void taskcomplete(){

// getprogressobserver().setstopped(false);

// }

}

testprogressgauge.java

/*

* created on 2005-2-26

*

* todo to change the template for this generated file go to

* 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 for 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 will jump to the main form",

null, alerttype.error);

alertscreen.settimeout(alert.forever);

needalert = true;

//do something first

getprogressobserver().updateprogress(null);//手动更新

try {

thread.sleep(3000);

} catch (exception e) {

e.printstacktrace();

return false;

}

getprogressobserver().updateprogress("sleepd 3s…");//手动更新

//取消了此处的手动查询点

// if (getprogressobserver().isstopped())

// return;

getprogressobserver().updateprogress(null);//手动更新

//do something again

try {

thread.sleep(3000);

} catch (exception e) {

e.printstacktrace();

return false;

}

getprogressobserver().setmax();//手动更新

display.setcurrent(new form("complete"));//跳转成功画面

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();

}

}

}

/////////////////////////////////////////////////////////////////

赞(0)
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » 再议j2me进度条与线程化模型-JSP教程,J2ME开发
分享到: 更多 (0)

相关推荐

  • 暂无文章