网站首页 新闻首页 网页设计图形动画软件编程网站开发办公软件操作系统数据库网络技术认证考试范文资料黑客攻防 书籍教程 进入论坛

再议j2me进度条与线程化模型

http://www.diybl.com/ 2007-2-6  网络 点击:  [ 评论 ]
文章搜索:    【点击打包该文章】

作者: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.Progres

欢迎光临DIY部落,点击这里查看更多文章教程   【点击打包该文章】
如果图片或页面不能正常显示请点击这里 站内搜索:   

文章评论

请您留言