知识大全 多线程在JAVA ME应用程序中的使用

Posted

篇首语:任何事情的发生必有其目的,并且有助于我。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 多线程在JAVA ME应用程序中的使用相关的知识,希望对你有一定的参考价值。

多线程在JAVA ME应用程序中的使用  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  多线程技术是JAVA ME中的关键技术 应用十分频繁 尤其是在游戏中 但是对于新手来说 又容易忽略或错误的使用多线程 导致程序堵塞 而无法响应用户的输入请求     由于笔者对于游戏开发不是十分了解 所以本文将仅就多线程技术在JAVA ME应用程序中的使用展开讨论 本文主要包含如下部分

         多线程与联网          多线程与拍照          Timer与TimerTask

  多线程与联网

  手机中 所有的MIDlet程序都是由Application Manager Sofare(AMS)管理的 当MIDlet初始化后 AMS就会调用MIDlet的startApp()方法 此时MIDlet就进入了Acitive状态 在JAVA ME中有些操作可能会导致程序堵塞 比如连接网络等 如果这些操作与主程序在同一个主线程中完成 那么由于堵塞会造成程序长时间无法返回 也就无法响应用户的其他操作了 所以 如果我们在mandAction()中进行了联网的操作 则会造成如上所述的情况    下面 将通过一个例子来演示如上的情况 并使用多线程最终解决此问题 这是一个 Echo Message 实例 手机端向服务器端发送一条消息 服务器得到此消息后直接返回给手机端    首先 创建一个NeorkConnection类来封装联网相关的操作 这样 MIDlet中只需调用此类中的方法就可以完成联网的操作 代码如下

   以下是引用片段 /*  * NeorkConnection java  *  * Created on  年 月 日  下午 :  *  */ package njunnection; import java io DataInputStream; import java io DataOutputStream; import java io IOException; import javax microedition io Connector; import javax microedition io HttpConnection; /**  *  * @author Magic  */ public class NeorkConnection      private static final String URL = //localhost: /thread/ ;     private HttpConnection Connection;     private String message;          public NeorkConnection(String message)          ssage = message;         connect();               /**      * Connect to web server      *      */     public void connect()         try              Connection = (HttpConnection) Connector open(URL);             (HttpConnection POST);          catch (IOException ex)              System out println( Can not open connection! );             ex printStackTrace();                             /**      * Send message to server      * @throws java io IOException       */     public void sendMessage() throws IOException         DataOutputStream out = ();         out writeUTF(message);         out close();               /**      * Receive message from server      * @throws java io IOException       * @return       */     public String receiveMessage() throws IOException          DataInputStream in = ();         String message = in readUTF();         in close();         return message;               /**      * Close connection      */     public void close()         if(Connection!=null)             try                  ();              catch (IOException ex)                  ex printStackTrace();                                     构造函数的参数是将要被发送的消息 服务器端的代码在此不再列出 详细请见本文的源代码     接着 我们写一个MIDlet调用类中的方法 MalConnectionMidlet在mandAction()方法中直接调用NeorkConnection中的方法 而没有重新创建一个线程 代码如下

   以下是引用片段 /*  * MalConnectionMidlet java  *  * Created on  年 月 日  下午 :  */ package njunnection; import java io IOException; import javax microedition midlet *; import javax microedition lcdui *; /**  *  * @author  Magic  * @version  */ public class MalConnectionMidlet extends MIDlet implements CommandListener      private Display display;     private TextBox text;     private Command showCommand;          public MalConnectionMidlet()         display = Display getDisplay(this);         text = new TextBox( Message 请使用 问候 命令发送消息 TextField ANY);         showCommand = new Command( 问候 Command SCREEN );         text addCommand(showCommand);         text setCommandListener(this);               public void startApp()          display setCurrent(text);               public void pauseApp()                public void destroyApp(boolean unconditional)           public void mandAction(Command mand  Displayable displayable)          if(mand==showCommand)             /**              *  在当前的线程中直接进行联网操作 造成程序堵塞        */             String message = null;                          NeorkConnection connection = new NeorkConnection( Hello World );             try                  connection sendMessage();                 message = connection receiveMessage();                 connection close();              catch (IOException ex)                  ex printStackTrace();                          text setString(message);                   当用户按下 问候 命令时 就会向服务器发送 Hello World 的消息 然后再得到服务器返回的消息 并显示在TextBox中     运行程序 如图 所示 当用户按下 问候 命令后 程序就僵死了 并在Console窗口中得到如下警告

  

  图

   以下是引用片段 Warning: To avoid potential deadlock  operations that may block  such as   neorking  should be performed in a different thread than the   mandAction() handler

  这就是因为没有使用多线程造成的 下面 就来看看如何使用多线程来解决此问题

  [NextPage]

  新建类NeorkThread 它继承在Thread 并将原先mandAction()中发送 接受消息的操作移到此类中完成 代码如下

   以下是引用片段 /*  * NeorkThread java  *  * Created on  年 月 日  下午 :  *  */ package njunnection; import java io IOException; import javax microedition lcdui TextBox; /**  *  * @author Magic  */ public class NeorkThread extends Thread      private NeorkConnection connection;     private TextBox text;          public NeorkThread(TextBox text)          super();         this text = text;          public void run()          String message = null;                      connection = new NeorkConnection( Hello World );         try              connection sendMessage();             message = connection receiveMessage();             connection close();          catch (IOException ex)              ex printStackTrace();                  text setString(message);               同时 修改原先的MIDlet 得到新的MIDlet

   以下是引用片段 /*  * ConnectionMidlet java  *  * Created on  年 月 日  下午 :  */ package njunnection; import java io IOException; import javax microedition midlet *; import javax microedition lcdui *; /**  *  * @author  Magic  * @version  */ public class ConnectionMidlet extends MIDlet implements CommandListener      private Display display;     private TextBox text;     private Command showCommand;          public ConnectionMidlet()         display = Display getDisplay(this);         text = new TextBox( Message 请使用 问候 命令发送消息 TextField ANY);         showCommand = new Command( 问候 Command SCREEN );         text addCommand(showCommand);         text setCommandListener(this);               public void startApp()          display setCurrent(text);               public void pauseApp()                public void destroyApp(boolean unconditional)           public void mandAction(Command mand  Displayable displayable)          if(mand==showCommand)             /**              * 创建新的线程完成联网操作              */             (new NeorkThread(text)) start();                   此时 在mandAction()中 我们创建了新的线程来完成消息的发送和接受 运行程序 可以成功接受到返回的消息 如图 所示

  

  图

  多线程与拍照

  同样 在移动多媒体API(JSR )的使用过程中也需要应用到多线程 利用手机摄像头拍照的操作也会引起的堵塞 因此当在mandAction()中调用拍照操作时 若未开辟新线程来处理 同样也会造成程序没有响应 让我们通过一个例子来观察一下吧     这是一个很简单的摄像头程序 首先程序将会调用摄像头取景 然后当用户按下 拍照 命令后就捕捉当前的画面并显示给用户 图 是程序的UML类图

  

  图

  MalCameraMidlet和CameraMidlet分别是错误和正确的MIDlet 它们都创建一个CameraView(用于显示摄像头画面)的对象 唯一的不同在于前者创建MalCamera的对象 后者创建Camera的对象(MalCamera和Camera都是CameraView的子类) SnapShot则是将摄像头捕捉到的图像显示给用户的类     首先 我们还是来看一下未使用多线程 而造成程序没有响应的情况 如下是MalCameraMidlet类的代码 其中保存著一个指向CameraView的引用 并在startApp()中创建了MalCamera对象

   以下是引用片段 /**  * MalCameraMidlet java  *   */ package nju hysteria thread camera; import javax microedition lcdui Display; import javax microedition midlet MIDlet; /**  * This MIDlet create the mal camera view  so the program  * will block after calling Capture mand  * @author Magic  *  */ public class MalCameraMidlet extends MIDlet   protected Display display;  private CameraView camera;    public MalCameraMidlet()    super();   display = Display getDisplay(this);    protected void startApp()    camera = new MalCamera(this);   display setCurrent(camera);            /**         * Show current camera         */  public void showCamera()   display setCurrent(camera);      protected void pauseApp()     protected void destroyApp(boolean arg )        CameraView是一个抽象类 是两个显示Camera的类的父类 它负责显示Camera 并将mandAction()方法留给子类实现 代码如下

   以下是引用片段 /**  * CameraView java  */ package nju hysteria thread camera; import java io IOException; import javax microedition lcdui Command; import javax microedition lcdui CommandListener; import javax microedition lcdui Displayable; import javax microedition lcdui Form; import javax microedition lcdui Item; import jadia Manager; import jadia MediaException; import jadia Player; import jantrol VideoControl; import javax microedition midlet MIDlet; /**  * This is an abstract class  which display camera to user  * @author Magic  *  */ public abstract class CameraView extends Form implements CommandListener   protected MIDlet midlet;  protected Player player;  protected VideoControl vc;  protected Command exitCommand;  protected Command captureCommand;    protected CameraView(MIDlet midlet)   super( 照相 );   this midlet = midlet;      exitCommand = new Command( 退出 Command EXIT );   captureCommand = new Command( 拍照 Command SCREEN );      addCommand(exitCommand);   addCommand(captureCommand);      setCommandListener(this);      /**    * Create camera player and control    */   try     player = Manager createPlayer( capture://video );    player realize();        vc = (VideoControl)player getControl( VideoControl );    append((Item)vc initDisplayMode(VideoControl USE_GUI_PRIMITIVE null));    player start();    catch (IOException e)     e printStackTrace();    catch (MediaException e)     e printStackTrace();         public abstract void mandAction(Command cmd Displayable displayable);

  [NextPage]

  MalCamera和Camera都继承了CameraView类 并分别实现了mandAction()方法 先来看一下MalCamera

   以下是引用片段 /**  * MalCamera java  */ package nju hysteria thread camera; import javax microedition lcdui Command; import javax microedition lcdui Displayable; import jadia MediaException; import javax microedition midlet MIDlet; /**  * This class display the mal camera  In mandAction()  * for capture mand  just get the data without create a   * new thread  and thus cause program blocked  * @author Magic  *  */ public class MalCamera extends CameraView     public MalCamera(MIDlet midlet)   super(midlet);      public void mandAction(Command cmd  Displayable displayable)    if(cmd==exitCommand)    try      player stop();     catch (MediaException e)      e printStackTrace();        player close();    ((MalCameraMidlet)midlet) destroyApp(false);    midlet notifyDestroyed();   else if(cmd==captureCommand)    // Do not handle in a new thread    try      byte[] data = vc getSnapshot(null);     new SnapShot(midlet data);     catch (MediaException e)      e printStackTrace();              其中SnapShot是显示捕捉到的图像的界面 详细请看文后的源代码 这里不再赘述     现在运行MalCameraMidlet 按下 拍照 命令后 出现询问是否记录图像的提示 但是 当你按下Yes后程序就再也没有响应了 如图 所示

  

  图

  查看控制台窗口 得到如下提示

   以下是引用片段 Warning: To avoid potential deadlock  operations that may block  such as   neorking  should be performed in a different thread than the   mandAction() handler

  同样 还是由于没有创建新的线程进行处理的原因 下面 我们就把处理的代码放到新的线程中来完成 看看情况如何 如下是修改过的MalCamera代码 Camera java:

   以下是引用片段 /**  * Camera java  */ package nju hysteria thread camera; import javax microedition lcdui Command; import javax microedition lcdui Displayable; import jadia MediaException; import javax microedition midlet MIDlet; /**  * This class displays camera  And do the right thing   * for capture mand  putting code in a new thread  * @author Magic  *  */ public class Camera extends CameraView   public Camera(MIDlet midlet)   super(midlet);      public void mandAction(Command cmd  Displayable displayable)    if(cmd==exitCommand)    try      player stop();     catch (MediaException e)      e printStackTrace();        player close();    ((CameraMidlet)midlet) destroyApp(false);    midlet notifyDestroyed();   else if(cmd==captureCommand)    // Handle in a new thread    new Thread()     public void run()      try        byte[] data = vc getSnapshot(null);       new SnapShot(midlet data);       catch (MediaException e)        e printStackTrace();                start();          同样 我们也需要在MIDlet中创建Camera的对象 而不是MalCamera CameraMidlet的代码如下

   以下是引用片段 /**  * CameraMidlet java  */ package nju hysteria thread camera; import javax microedition lcdui Display; import javax microedition midlet MIDlet; /**  * The correct MIDlet  * @author Magic  *  */ public class CameraMidlet extends MIDlet   protected Display display;  private CameraView camera;    public CameraMidlet()    super();   display = Display getDisplay(this);    protected void startApp()    camera = new Camera(this);   display setCurrent(camera);          /**         * Show current camera         */  public void showCamera()   display setCurrent(camera);      protected void pauseApp()     protected void destroyApp(boolean arg )        运行CameraMidlet 按下 拍照 命令 这次程序没有堵塞 我们可以得到捕捉到的图片 如图 所示

  

  图

   

  [NextPage]

  Timer与TimerTask

  联网和拍照这两种情况都需要程序员创建新的线程来完成任务 并且这种做法对于程序员来说是显式的 即通过直接使用Thread类或Runnable接口来直接创建新线程 在MIDP的API中同样提供了隐式的方式来创建新线程 以方便程序员的编程 这就是TimerTask类 它实现了Runnable接口 用户只需创建一个继承它的类 并且实现run()方法 以此来创建新线程 而无需显示的继承Thread或Runnable     当然 TimerTask的优点不仅于此 从它的名字来看 可以认为它是一个在特定时间执行的任务 run()方法中代码就是这任务 那么怎么控制其在特定时间执行呢?这就需要Timer这个类的帮助了 顾名思义 Timer是一个定时器 通过调用它的多个schedule( )方法中的一个 可以控制在特定的时间 或每隔一定时间执行TimerTask 具体的方法介绍请看JDK文档     TimerTask和Timer经常一起使用 比如在显示时间 倒计时和显示欢迎界面时会经常用到 下面 就通过一个实例来介绍这两个的用法     这是一个计时的程序 程序从 秒开始 用户可以随时暂停或继续计时 程序是通过Timer和TimerTask来完成的 包含三个类 ClockMidlet ClockCanvas和Clock 首先来看一下本程序最主要的类ClockCanvas

   以下是引用片段 /**  * ClockCanvas java  */ package nju hysteria thread clock; import java util Timer; import javax microedition lcdui Canvas; import javax microedition lcdui Command; import javax microedition lcdui CommandListener; import javax microedition lcdui Displayable; import javax microedition lcdui Font; import javax microedition lcdui Graphics; /**  * This class display time to user  and also start the timer  * to update time each second  * @author Magic  *  */ public class ClockCanvas extends Canvas implements CommandListener   private ClockMidlet midlet;  private Command exitCommand;  private Command stopCommand;  private Command resumeCommand;  private long second;  private int x;  private int y;   // Timer  private Timer timer;    public ClockCanvas(ClockMidlet midlet)   this midlet = midlet;   exitCommand = new Command( 退出 Command EXIT );   stopCommand = new Command( 停止 Command SCREEN );   resumeCommand = new Command( 继续 Command SCREEN );      addCommand(exitCommand);   addCommand(stopCommand);   setCommandListener(this);      second =  ;   x = getWidth()/     ;   y = getHeight()/     ;    // Create timer and start it   timer = new Timer();   timer schedule(new Clock(this) );      /**   * Add one second   *   */  public void addSecond()   second++;      protected void paint(Graphics g)    g setColor( );   g fillRect( getWidth() getHeight());   g setColor( );   g setFont(Font getFont(Font FACE_SYSTEM Font STYLE_PLAIN Font SIZE_LARGE));   // Draw second   g drawString(String valueOf(second) x y Graphics LEFT|Graphics TOP);    public void mandAction(Command cmd  Displayable displayable)    if(cmd==exitCommand)    timer cancel();    midlet destroyApp(false);    midlet notifyDestroyed();   else if (cmd==stopCommand)    timer cancel();    removeCommand(stopCommand);    addCommand(resumeCommand);   else if (cmd==resumeCommand) timer = null;    timer = new Timer();    timer schedule(new Clock(this) );    removeCommand(resumeCommand);    addCommand(stopCommand);          ClockCanvas继承了Canvas 用来向用户显示当前的秒数 注意构造函数中黑体的代码 创建了Timer 并且调用schedule()方法来设定运行任务的时间 第一个参数是TimerTask的对象 这里是Clock 它继承了TimerTask 我们将稍后讨论 第二个参数是运行的延迟 这里为 也就是立刻执行 第三个参数是连续运行的时间间隔 这里为 毫秒 也就是每隔 秒钟更新界面     注意mandAction()方法 在处理 停止 命令时 需要停止计时 此处调用timer cancle()来取消计时器 所以界面将停止更新 当按下 继续 命令后 又需要继续开始计时 所以我们重新创建了Timer 因为原来的已经取消了 是不可用的了     接着就来看看Clock是如何来工作的 代码如下

   以下是引用片段 /**  * Clock java  */ package nju hysteria thread clock; import java util TimerTask; /**  * Update the time  * @author Magic  *  */ public class Clock extends TimerTask   private ClockCanvas canvas;    public Clock(ClockCanvas canvas)   this canvas = canvas;      public void run()    canvas addSecond();   canvas repaint();  

  非常简单 在run()方法中就是调用了ClockCanvas类中addSencond()方法来增加时间 同时调用repaint()来更新界面 从表面上看几乎没有多线程的痕迹 其实创建Timer的时候就相当于在后台创建了一个新的线程 它控制着TimerTask的执行 因此对于秒数的增加是在另一个线程的完成的 而主线程只负责更新显示    在加上下面的ClockMidlet就可以运行程序了

   以下是引用片段 /**  * ClockMidlet java  */ package nju hysteria thread clock; import javax microedition lcdui Canvas; import javax microedition lcdui Display; import javax microedition midlet MIDlet; /**  * Clock MIDlet  * @author Magic  *  */ public class ClockMidlet extends MIDlet   private Display display;  private Canvas clockCanvas;    public ClockMidlet()    super();   display = Display getDisplay(this);    protected void startApp()   clockCanvas = new ClockCanvas(this);   display setCurrent(clockCanvas);    protected void pauseApp()     protected void destroyApp(boolean arg )       运行程序 将以秒为单位进行计时 如图 所示

  

  图

  总  结

cha138/Article/program/Java/gj/201311/27462

相关参考

知识大全 Java 程序中的多线程(四)

Java程序中的多线程(四)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  作者NeelVKum

知识大全 Java 程序中的多线程(二)

Java程序中的多线程(二)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  作者NeelVKum

知识大全 Java 程序中的多线程(一)

Java程序中的多线程(一)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  作者NeelVKum

知识大全 java多线程中的异常处理

  在java多线程程序中所有线程都不允许抛出未捕获的checkedexception也就是说各个线程需要自己把自己的checkedexception处理掉这一点是通过javalangRunnable

知识大全 java多线程小结

  /*进程是一个正在执行的程序  *每一个进程执行都有一个执行顺序该顺序是一个执行路径或者叫一个控制单元  *  *线程就是进程中的一个独立的控制单元  *   线程在

知识大全 用Java实现多线程服务器程序

用Java实现多线程服务器程序  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  摘要在Java出现

知识大全 构建多线程Java应用程序

构建多线程Java应用程序  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  大多数服务端应用程序都

知识大全 J2ME中实现多线程技术总结

J2ME中实现多线程技术总结  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  我们知道在操作系统级

知识大全 Java多线程应用方法全解密

Java多线程应用方法全解密  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  Java多线程是我们

知识大全 Java多线程程序如何掌握基本语法

Java多线程程序如何掌握基本语法  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  Java多线程