动态网站制作指南 [  QQ表情  ]
[ 投票调查 ]
[ 企业邮箱 ]
[ 网站空间 ]
网络编程 | 站长之家 | 网页制作 | 图形图象 | 操作系统 | 冲浪宝典 | 软件教学 | 网络办公 | 邮件系统 | 网络安全 | 认证考试 | 系统进程
ASP源码 | .Net源码 | PHP源码 | JSP源码 | JAVA源码 | CGI源码 | VB源码 | C++源码 | Delphi源码 | PB源码 | VF源码 | 汇编 | 服务器
Firefox | IE | Maxthon | 迅雷 | 电驴 | BitComet | FlashGet | QQ | QQ空间 | Vista | 输入法 | Ghost | Word | Excel | wps | Powerpoint
asp | .net | php | jsp | Sql | c# | Ajax | xml | Dreamweaver | FrontPages | Javascript | css | photoshop | fireworks | Flash | Cad | Discuz!
当前位置 > 网站建设学院 > 网络编程 > J2EE/J2ME教程
Tag:注入,存储过程,分页,安全,优化,xmlhttp,fso,jmail,application,session,防盗链,stream,无组件,组件,md5,乱码,缓存,加密,验证码,算法,cookies,ubb,正则表达式,水印,索引,日志,压缩,base64,url重写,上传,控件,Web.config,JDBC,函数,内存,PDF,迁移,结构,破解,编译,配置,进程,分词,IIS,Apache,Tomcat,phpmyadmin,Gzip,触发器,socket
网络编程:ASP教程,ASP.NET教程,PHP教程,JSP教程,C#教程,数据库,XML教程,Ajax,Java,Perl,Shell,VB教程,Delphi,C/C++教程,软件工程,J2EE/J2ME,移动开发
文章搜索服务
邮件订阅
输入你的邮件地址,
你将不会错过任何关于:
[ J2EE/J2ME教程 ]的信息

本月文章推荐
.EnterpriseJavaBeans导论七.
.精通Hibernate映射继承关系之四.
.保护MIDP应用里的数据文件--远离.
.使用MMAPI播放多媒体文件.
.J2EE 探索:有状态网络的 J2EE 技.
.JBOSSAOP学习笔记-标签使用(J2SE.
.JavaMail快速入门-3.
.Tomcat5集群中的SESSION复制第一.
.J2EE、Linux稳固e-business架构.
.Petstore源码追踪记(3)-商业逻辑.
.Petstore源码追踪记(3)-商业逻辑.
.JavaMail快速入门-6.
.JavaMail快速入门-4.
.使用POST和GET方法与servlet通信.
.创建灵活易扩展的J2EE企业应用程.
.J2me性能优化,避免内存溢出小结.
.精通Hibernate映射继承关系之六.
.获得Spring Bean.
.使用Servlet发送电子邮件.
.RMS概念解析与使用指南.

j2me进度条与线程化模型

发表日期:2007-12-23 |


j2me进度条与线程化模型

作者:FavoYang       Email:favoyang@yahoo.com 欢迎交流
Keyworld:线程化模型 j2me UI设计

内容提要:
本文研究如何建立一个方便使用的线程化模型,这个线程化模型由前台的进度条UI 和后台的背景线程组成。

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

正文:

解决的问题

在j2me的UI体系中,UI操作是在一个独立的线程中运行的。往往在api doc中要求程序员对接口方法立即返回。也就是说非阻塞的。你必须开启一个独立的线程来完成你自定义的复杂的工作,比如联网等可能发生阻塞的io操作。新的线程如果不和用户交流,告诉用户线程正在工作的话,将会显现的非常不友好。用户可能执行别的操作而扰乱程序的正常运行。一个简单的方法是提供一个进度条,这样用户就会愿意等待上一会,直到程序运行出结果。为了将程序员从前台进度条与后台线程的通信中解脱出来,专心于后台线程的开发,有必要设计一个进度条线程模型。

应该注意到进度条有多种的形式:
 
A, 动画形式进度条,仅表示程序正在运行(自维护的)
B, 可交互增量形式的进度条,后台线程通过调用进度条的相应方法在程序运行中不断的改变进度条的状态
C, 进度条的表现形式应该灵活,不要固定其实现
D, 进度条对象要重复利用

j2me进度条与线程化模型(图一)

进度调和后台线程的交流也有好几种情况:
A, 仅仅将进度条绘画在屏幕上,并等后台任务完成后,由后台线程跳转到成功画面。
B, 对于可取消的任务,用户可以通过点击进度条的按钮来试图cancel任务,后台任务应该尽快取消,并跳转到失败的画面
C, 对于不可跳转的任务,用户只有耐心等待
D, 如果背景线程运行失败,应自行跳转到失败的屏幕

进度条的设计(前台)

为了实现进度条的表现的多样性,首先抽象一个接口:
ProgressObserver.Java
package com.favo.ui;
import javax.microedition.lcdui.Display;

/**
 * @author Favo
 *
 * 这是仿照Smart Ticket制作的进度条观察者,这个模型的优点是
 * 1,低耦合度。你可以通过Form,Canvas等来实现这个接口
 * 2,支持可中断的任务,因为背景线程是无法强制性中断的,
 * 所以就 没有了在观察者中回调背景线程相应方法的必要,
 * 如果支持可中断的话,可以让背景线程来查询观察者的isStopped()
 * 3,可以说进度条仅仅将自己绘画在屏幕上,他对后台线程毫不关心
 */
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();

 public void setStoppable(boolean stoppable);

 public boolean isStopped();

 public void setStopped(boolean stopped);

 public void setTitle(String title);

 public void setPrompt(String prompt);
}

每个方法都很一幕了然,我解释两点:
1)“2,支持可中断的任务,因为背景线程是无法强制性中断的, 所以就 没有了在观察者中回调背景线程相应方法的必要, 如果支持可中断的话,可以让背景线程来查询观察者的isStopped()”
如果要支持可中断线程的话,想当然的,我们希望用户按下按钮后回调后台线程的某个方法来停止线程,并且这个方法要立即返回(前面提过UI的用户响应不能够阻塞)。但是细细想想,线程是无法被强制停止的,而且即使能够被强制停止也很不安全。所以这个方法也只能够是通过设置某个flag,然后立即返回。这样的话线程就和前台的UI紧密的耦合在一起了。与其这样,倒不如让后台线程去查询UI的状态。这样UI并不关心到底是谁在后台维护他状态。


2)如果要实现一个不交互动画UI,那么显然这个UI是自维护的(也就是说UI单独有自己的绘画线程)。为了能够实现这种情况,可以在show中开启线程,在exit中结束线程。对于交互UI,可以简单的忽略exit方法。

下面给一个利用Form和Gauge实现的交互式UI(非自维护的),读者可以看看其中的细节,参照他可以设计自己的用Canvas实现的,或者自维护的等等不同的实现。
ProgressGaugeUI.java
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
 * 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;

 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;
 }

 public void reset() {
  current=0;
  gauge.setValue(0);
  stopped=false;
  setStoppable(false);
  setTitle("");
  setPrompt("");
 }

 public void updateProgress(Object param1) {//这里的参数设计为提示语
  current=(current+1)%GAUGE_LEVELS;
  gauge.setValue(current * GAUGE_MAX/GAUGE_LEVELS);
  if(param1!=null && param1 instanceof String){
   setPrompt((String)param1);
  }
 }

 public boolean isStoppable() {
  return stoppable;
 }

 public void setStoppable(boolean stoppable) {
  this.stoppable = stoppable;
  if(stoppable){
   f.addCommand(stopCMD);
  }else{
   f.removeCommand(stopCMD);
  }
 }

 public boolean isStopped() {
  return stopped;
 }

public void setStopped(boolean stopped) {
  this.stopped=stopped;
 }

 public void setTitle(String title) {
  f.setTitle(title);
 }

 public void setPrompt(String prompt) {
  gauge.setLabel(prompt);
 }

 public void commandAction(Command arg0, Displayable arg1) {
  if(arg0==stopCMD){
   if(isStoppable())
    stopped=true;
   else{
    setPrompt("can't stop!");
   }
  }
 }


 public void show(Display display) {
  display.setCurrent(f);
 }
public void exit() {
  // 忽略
 }
 public void setMax() {
  gauge.setValue(GAUGE_MAX);
 }
}

后台线程的设计


后台线程替我们作以下的内容:
1)执行我们的任务runTask()
2)如果用户中断线程,那么runTask()运行完后,将会跳转到我们指定的失败屏幕
3)在最后替我们调用UI.exit()

我们需要做的:
1)提供一个前台的UI,提供失败后跳转的画面,提供Display的实例
2)在runTask()中,如果任务完成,手工跳转失败画面
3)在runTask()中,如果任务失败,手工跳转失败画面
4)在runTask()中改变进度栏的状态。
5)在runTask()中查询用户是否取消,如果用户取消,应该尽快退出runTask()

这种模型职责清晰,便于使用。但也有一个缺点:如果用户取消了任务,但是此时任务接近完成,或者已经完成。后台线程依然会显示用户取消了任务,并将会跳转到我们指定的失败屏幕。这时候会产生不一致的情况。为了解决整个问题,程序员可以在runTask()中调用taskComplete()来强制完成任务。这样即使用户取消了任务,依然回显示任务成功。当然你也可以不掉用taskComplete()遵循默认的行为特点。

BackgroundTask.java
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
 * Preferences - Java - Code Style - Code Templates
 */
public abstract class BackgroundTask extends Thread {

 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;
 }

 public void run() {
  try {
   runTask();
  } catch (Exception e) {
   Alert al = new Alert("undefine exception",
e.getMessage(), null,
                       AlertType.ALARM);
   al.setTimeout(Alert.FOREVER);
   display.setCurrent(al);
  } finally {
   if (poUI.isStoppable()) {
    if (poUI.isStopped()) {//如果用户中断了程序
     if (needAlert) {
      display.setCurrent(alertScreen, preScreen);
     } else {
      display.setCurrent(preScreen);
     }
    }
   }
   poUI.exit();
  }
 }

 /*
  * 如果任务可中断,查看pgUI.isStopped().并尽快退出此方法;
 * 如果任务需要更新进度栏,调用pgUI.updateProgress(“进度提示”).
 * 习惯上此方法的最后手动调用taskComplete()以防止用户在任务接近
 * 完成时取消
  */
 public abstract void 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);
  po.setTitle(title);
  po.setPrompt(prompt);
  po.show(display);
  btask.start();
 }

 public ProgressObserver getProgressObserver() {
  return poUI;
 }
 
 public void taskComplete(){
  getProgressObserver().setStopped(false);
 }
}


如何使用


1)产生一个ProgressObserver 对象poUI
如果用默认的,通过调用ProgressGaugeUI.getInstance();
2)构造BackgroundTask对象bkTask,一般可以用匿名类来实现。
3)初始化poUI-->设置后字段-->显示你的poUI-->开启bkTask线程。
第三步可以用一步完成,通过调用静态方法
BackgroundTask.runWithProgressGauge(bkTask, "标题","提示", 是否可以暂停, display);

下面一个例子,看看你是否理解了,并且会使用了。
TestProgressGauge.java
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
* 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);
 }

 protected void startApp() throws MIDletStateChangeException {
  // TODO Auto-generated method stub
  display.setCurrent(f);
 }

 protected void pauseApp() {
  // TODO Auto-generated method stub

 }

 protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
 }


 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 void runTask() {
     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();
     }
     getProgressObserver().updateProgress("sleepd 3s...");
     if (getProgressObserver().isStopped())
      return;
     getProgressObserver().updateProgress(null);
     //do something second
     try {
      Thread.sleep(3000);
     } catch (Exception e) {
      e.printStackTrace();
     }
     getProgressObserver().setMax();
     display.setCurrent(new Form("complete"));
     taskComplete();
    }
   };
   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();
  }
 }

}
运行流程画面
j2me进度条与线程化模型(图二) 按下compute-->  j2me进度条与线程化模型(图三) 用户取消-->
j2me进度条与线程化模型(图四) 回到前一屏幕-->  j2me进度条与线程化模型(图五) 按下compute-->
 j2me进度条与线程化模型(图三)--> j2me进度条与线程化模型(图六) -->j2me进度条与线程化模型(图七)完成


希望这个模型可以加快你的开发速度。如果你有更好的解决办法,能够更清晰的解决问题或是问题的细节,欢迎讨论。

(出处:http://www.knowsky.com)


上一篇:再议j2me进度条与线程化模型 人气:638
下一篇:RMS概念解析与使用指南 人气:737
浏览全部J2EE/J2ME的内容 Dreamweaver插件下载 常用网页广告代码全集
  最新网站源码 最新软件下载
2008-12-1 MyBB v1.4.4 简体中文版 bulid 2
2008-12-1 新云网站内容管理系统 v4.0.0.11
2008-12-1 网趣网上购物系统时尚版 v8.8
2008-12-1 Textpattern v4.0.7 多国语言版
2008-12-1 Piwik ( PHP统计系统,可以和GOOG
2008-12-1 天空网络电影系统SKYUC! v2.6.2
2008-12-1 SiteDynamic企业网站管理系统 v1
2008-12-1 KindEditor HTML在线编辑器 v3.0
2008-12-1 0451sky高校教务管理系统2008 v4
2008-11-29 Tencent Traveler 4.4
2008-11-29 龙卷风网络收音机 v3.0.0.0
2008-11-29 Intel Chipset Software Install
2008-11-29 TweakVI 1.0 Build 1100
2008-11-29 Opera 9.62 Build 10469
2008-11-29 MPlayer WW编译版 SVN-r28044(20
2008-11-29 NetTools网络工具v1.0.0破解版
2008-11-29 3DGallery三维体验1.1破解版
2008-11-29 SecretBook保密本v1.0破解版
  发表评论
姓 名: 验证码:
内 容:
站长工具:网站收录查询 | Google PR查询 | ALEXA排名查询 | CSS在线编辑器 | OPEN参数生成器 | 弹出式窗口代码产生器 | 密码登录生成器 | 在线按钮生成器 | Meta标签生成器 | 多色彩特效字代码生成器 | 网页代码调试器 | 在线FTP登陆 | Flash取色器 | 配色代码对照表 | 配色辞典 | CSS生成器 | 广告代码 | 框架网页代码生成器 | js/vbs加密 | md5加密 | 进制转换 | UTF-8 转换工具 | 在线调色板 | Html转换js | Html转换asp | Html转换php | Html转换perl
实用工具:汉字翻译拼音 | 拼音字典 | 符号对照表 | 个税计算 | 实时汇率查询换算 | 经典小工具 | 汉字简繁转换 | 普通单位换算 | 公制单位换算 | 生辰老黄历 | 国内电话区号 | 国家代码与域名缩写 | 文字加密解密 | 元素周期表 | 健康查询 | 世界时间 | 万年历 | 二十四节气 | 汉字横竖排版 | 手机号码查询 | 计算器 | ip搜索
业务联系 | 广告刊登 | 频道合作 | 投稿荐稿 | 联系方式 | 加入收藏 | RSS订阅
Copyright © 2000-2009 www.knowsky.com All rights reserved | 沪ICP备05001343号
ホームページ制作 不動産検索システム 求人情報
防水工事·改修工事 フットサル大会 探偵
SEO対策 中国語教室 ホームページ作成