中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> 程序开发 > 编程语言 > Java > J2ME
J2ME蓝牙手机应用程序开发实战入门
作者:Jagie 时间:2006-09-22 09:16 出处:javaresearch 责编:月夜寒箫
              摘要:J2ME蓝牙手机应用程序开发实战入门
目前,很多手机已经具备了蓝牙功能。虽然MIDP2.0没有包括蓝牙API,但是JCP定义了JSR82, Java APIs for Bluetooth Wireless Technology (JABWT).这是一个可选API,很多支持MIDP2.0的手机已经实现了,比如Nokia 6600, Nokia 6670,Nokia7610等等。对于一个开发者来说,如果目标平台支持JSR82的话,在制作联网对战类型游戏或者应用的时候,蓝牙是一个相当不错的选择。

本文给出了一个最简单的蓝牙应用的J2ME程序,用以帮助开发者快速的掌握JSR82。该程序分别在2台蓝牙设备上安装后,一台设备作为服务端先运行,一台设备作为客户端后运行。在服务端上我们发布了一个服务,该服务的功能是把客户端发过来的字符串转变为大写字符串。客户端起动并搜索到服务端的服务后,我们就可以从客户端的输入框里输入任意的字符串,发送到服务端去,同时观察服务端的反馈结果。

实例代码

该程序包括3个java文件。一个是MIDlet,另外2个为服务端GUI和客户端GUI。该程序已经在wtk22模拟器和Nokia 6600,Nokia 6670两款手机上测试通过。

StupidBTMIDlet.java
            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.List;
            import javax.microedition.midlet.MIDlet;
            import javax.microedition.midlet.
            MIDletStateChangeException;
            /**
            * @author Jagie
            *
            *  MIDlet
            */
            public class StupidBTMIDlet extends
            MIDlet implements CommandListener
            {
            List list;
            ServerBox sb;
            ClientBox cb;
            /*
            * (non-Javadoc)
            *
            * @see javax.microedition.
            midlet.MIDlet#startApp()
            */
            protected void startApp()
            throws MIDletStateChangeException
            {
            list = new List
            ("蓝牙入门", List.IMPLICIT);
            list.append("Client", null);
            list.append("Server", null);
            list.setCommandListener(this);
            Display.getDisplay(this).setCurrent(list);
            }
            /**
            * debug方法
            * @param s 要显示的字串
            */
            public void showString(String s)
            {
            Displayable dp =
            Display.getDisplay(this).getCurrent();
            Alert al = new Alert(null, s,
            null, AlertType.INFO);
            al.setTimeout(2000);
            Display.getDisplay(this).setCurrent(al, dp);
            }
            /**
            * 显示主菜单
            *
            */
            public void showMainMenu()
            {
            Display.getDisplay(this).
            setCurrent(list);
            }
            protected void pauseApp()
            {
            // TODO Auto-generated method stub
            }
            public void commandAction
            (Command com, Displayable disp)
            {
            if (com == List.SELECT_COMMAND)
            {
            List list = (List) disp;
            int index = list.getSelectedIndex();
            if (index == 1)
            {
            if (sb == null)
            {
            sb = new ServerBox(this);
            }
            sb.setString(null);
            Display.getDisplay(this)
            .setCurrent(sb);
            } else {
            //每次都生成新的客户端实例
            cb = null;
            System.gc();
            cb = new ClientBox(this);
            Display.getDisplay(this)
            .setCurrent(cb);
            }
            }
            }
            protected void destroyApp(boolean arg0)
            throws MIDletStateChangeException
            {
            // TODO Auto-generated method stub
            }
            }
            ClientBox.java
            import java.io.DataInputStream;
            import java.io.DataOutputStream;
            import java.io.IOException;
            import java.util.Vector;
            import javax.microedition.io.Connector;
            import javax.microedition.io.StreamConnection;
            import javax.microedition.lcdui.Command;
            import javax.microedition.lcdui.CommandListener;
            import javax.microedition.lcdui.Displayable;
            import javax.microedition.lcdui.Form;
            import javax.microedition.lcdui.Gauge;
            import javax.microedition.lcdui.StringItem;
            import javax.microedition.lcdui.TextField;
            //jsr082 API
            import javax.bluetooth.BluetoothStateException;
            import javax.bluetooth.DeviceClass;
            import javax.bluetooth.DiscoveryAgent;
            import javax.bluetooth.DiscoveryListener;
            import javax.bluetooth.LocalDevice;
            import javax.bluetooth.RemoteDevice;
            import javax.bluetooth.ServiceRecord;
            import javax.bluetooth.UUID;
            /**
            * 客户端GUI
            * @author Jagie
            *
            * TODO To change the template for
            this generated type comment go to
            * Window - Preferences -
            Java - Code Style - Code Templates
            */
            public class ClientBox extends
            Form implements Runnable, CommandListener,
            DiscoveryListener
            {
            //字串输入框
            TextField input =
            new TextField(null, "", 50, TextField.ANY);
            //loger
            StringItem result =
            new StringItem("结果:", "");
            private DiscoveryAgent discoveryAgent;
            private UUID[] uuidSet;
            //响应服务的UUID
            private static final UUID
            ECHO_SERVER_UUID = new UUID(
            "F0E0D0C0B0A000908070605040302010", false);
            //设备集合
            Vector devices = new Vector();
            //服务集合
            Vector records = new Vector();
            //服务搜索的事务id集合
            int[] transIDs;
            StupidBTMIDlet midlet;
            public ClientBox(StupidBTMIDlet midlet)
            {
            super("");
            this.midlet=midlet;
            this.append(result);
            this.addCommand(new Command
            ("取消",Command.CANCEL,1));
            this.setCommandListener(this);
            new Thread(this).start();
            }
            public void commandAction
            (Command arg0, Displayable arg1)
            {
            if(arg0.getCommandType
            ()==Command.CANCEL){
            midlet.showMainMenu();
            }else{
            //匿名内部Thread,访问远程服务。
            Thread fetchThread=new Thread()
            {
            public void run()
            {
            for(int i=0;i<records.size();i++)
            {
            ServiceRecord sr=(ServiceRecord)
            records.elementAt(i);
            if(accessService(sr))
            {
            //访问到一个可用的服务即可
            break;
            }
            }
            }
            };
            fetchThread.start();
            }
            }
            private boolean  accessService
            (ServiceRecord sr)
            {
            boolean result=false;
            try {
            String url = sr.getConnectionURL(
            ServiceRecord.
            NOAUTHENTICATE_NOENCRYPT, false);
            StreamConnection
            conn = (StreamConnection)
            Connector.open(url);
            DataOutputStream dos=
            conn.openDataOutputStream();
            dos.writeUTF(input.getString());
            dos.close();
            DataInputStream dis=conn.openDataInputStream();
            String echo=dis.readUTF();
            dis.close();
            showInfo("反馈结果是:"+echo);
            result=true;
            } catch (IOException e)
            {
            }
            return result;
            }
            public synchronized void run()
            {
            //发现设备和服务的过程中,
            给用户以Gauge
            Gauge g=new Gauge(null,false,Gauge.INDEFINITE,
            Gauge.CONTINUOUS_RUNNING);
            this.append(g);
            showInfo("蓝牙初始化...");
            boolean isBTReady = false;
            try
            {
            LocalDevice localDevice
            = LocalDevice.getLocalDevice();
            discoveryAgent
            = localDevice.getDiscoveryAgent();
            isBTReady = true;
            } catch (Exception e)
            {
            e.printStackTrace();
            }
            if (!isBTReady)
            {
            showInfo("蓝牙不可用");
            //删除Gauge
            this.delete(1);
            return;
            }
            uuidSet = new UUID[2];
            //标志我们的响应服务的UUID集合
            uuidSet[0] = new UUID(0x1101);
            uuidSet[1] = ECHO_SERVER_UUID;
            try {
            discoveryAgent.startInquiry
            (DiscoveryAgent.GIAC, this);
            } catch (BluetoothStateException e)
            {
            }
            try {
            //阻塞,由inquiryCompleted()回调方法唤醒
            wait();
            } catch (InterruptedException e1)
            {
            e1.printStackTrace();
            }
            showInfo("设备搜索完毕,共找到"
            +devices.size()+"个设备,开始搜索服务");
            transIDs = new int[devices.size()];
            for (int i = 0; i < devices.size(); i++)
            {
            RemoteDevice rd = (RemoteDevice)
            devices.elementAt(i);
            try {
            //记录每一次服务搜索的事务id
            transIDs[i] =
            discoveryAgent.searchServices
            (null, uuidSet,
            rd, this);
            } catch (BluetoothStateException e)
            {
            continue;
            }
            }
            try {
            //阻塞,由serviceSearchCompleted()
            回调方法在所有设备都搜索完的情况下唤醒
            wait();
            } catch (InterruptedException e1)
            {
            e1.printStackTrace();
            }
            showInfo("服务搜索完毕,
            共找到"+records.size()+
            "个服务,准备发送请求");
            if(records.size()>0){
            this.append(input);
            this.addCommand(new Command
            ("发送",Command.OK,0));
            }
            //删除Gauge
            this.delete(1);
            }
            /**
            * debug
            * @param s
            */
            private void showInfo(String s){
            StringBuffer sb=new
            StringBuffer(result.getText());
            if(sb.length()>0){
            sb.append("\n");
            }
            sb.append(s);
            result.setText(sb.toString());
            }
            /**
            * 回调方法
            */
            public void deviceDiscovered
            (RemoteDevice btDevice, DeviceClass cod)
            {
            if (devices.indexOf(btDevice) == -1)
            {
            devices.addElement(btDevice);
            }
            }
            /**
            * 回调方法,唤醒初始化线程
            */
            public void inquiryCompleted(int discType)
            {
            synchronized (this)
            {
            notify();
            }
            }
            /**
            * 回调方法
            */
            public void servicesDiscovered
            (int transID, ServiceRecord[] servRecord)
            {
            for (int i = 0; i < servRecord.length; i++)
            {
            records.addElement(servRecord[i]);
            }
            }
            /**
            * 回调方法,唤醒初始化线程
            */
            public void serviceSearchCompleted
            (int transID, int respCode)
            {
            for (int i = 0; i < transIDs.length; i++)
            {
            if (transIDs[i] == transID)
            {
            transIDs[i] = -1;
            break;
            }
            }
            //如果所有的设备都已经搜索服务完毕,
            则唤醒初始化线程。
            boolean finished = true;
            for (int i = 0; i < transIDs.length; i++)
            {
            if (transIDs[i] != -1)
            {
            finished = false;
            break;
            }
            }
            if (finished)
            {
            synchronized (this)
            {
            notify();
            }
            }
            }
            }
            ServerBox.java
            import java.io.DataInputStream;
            import java.io.DataOutputStream;
            import java.io.IOException;
            import java.util.Vector;
            import javax.bluetooth.DiscoveryAgent;
            import javax.bluetooth.LocalDevice;
            import javax.bluetooth.ServiceRecord;
            import javax.bluetooth.UUID;
            import javax.microedition.io.Connector;
            import javax.microedition.io.StreamConnection;
            import javax.microedition.io.
            StreamConnectionNotifier;
            import javax.microedition.lcdui.Command;
            import javax.microedition.lcdui.CommandListener;
            import javax.microedition.lcdui.Displayable;
            import javax.microedition.lcdui.TextBox;
            import javax.microedition.lcdui.TextField;
            /**
            * 服务端GUI
            * @author Jagie
            *
            * TODO To change the template
            for this generated type comment go to
            * Window - Preferences
            - Java - Code Style - Code Templates
            */
            public class ServerBox extends
            TextBox implements Runnable, CommandListener
            {
            Command com_pub = new Command
            ("开启服务", Command.OK, 0);
            Command com_cancel = new Command
            ("终止服务", Command.CANCEL, 0);
            Command com_back = new Command
            ("返回", Command.BACK, 1);
            LocalDevice localDevice;
            StreamConnectionNotifier notifier;
            ServiceRecord record;
            boolean isClosed;
            ClientProcessor processor;
            StupidBTMIDlet midlet;
            //响应服务的uuid
            private static final UUID
            ECHO_SERVER_UUID = new UUID(
            "F0E0D0C0B0A000908070605040302010", false);
            public ServerBox(StupidBTMIDlet midlet)
            {
            super(null, "", 500, TextField.ANY);
            this.midlet = midlet;
            this.addCommand(com_pub);
            this.addCommand(com_back);
            this.setCommandListener(this);
            }
            public void run()
            {
            boolean isBTReady = false;
            try {
            localDevice =
            LocalDevice.getLocalDevice();
            if (!localDevice.setDiscoverable
            (DiscoveryAgent.GIAC))
            {
            showInfo("无法设置设备发现模式");
            return;
            }
            // prepare a URL to create a notifier
            StringBuffer url =
            new StringBuffer("btspp://");
            // indicate this is a server
            url.append("localhost").append(':');
            // add the UUID to identify this service
            url.append(ECHO_SERVER_UUID.toString());
            // add the name for our service
            url.append(";name=Echo Server");
            // request all of the
            client not to be authorized
            // some devices fail on authorize=true
            url.append(";authorize=false");
            // create notifier now
            notifier = (StreamConnectionNotifier)
            Connector
            .open(url.toString());
            record = localDevice.getRecord(notifier);
            // remember we've reached this point.
            isBTReady = true;
            } catch (Exception e) {
            e.printStackTrace();
            }
            // nothing to do if no bluetooth available
            if (isBTReady) {
            showInfo("初始化成功,等待连接");
            this.removeCommand(com_pub);
            this.addCommand(com_cancel);
            } else {
            showInfo("初始化失败,退出");
            return;
            }
            // 生成服务端服务线程对象
            processor = new ClientProcessor();
            // ok, start accepting connections then
            while (!isClosed) {
            StreamConnection conn = null;
            try {
            conn = notifier.acceptAndOpen();
            } catch (IOException e) {
            // wrong client or interrupted
            - continue anyway
            continue;
            }
            processor.addConnection(conn);
            }
            }
            public void publish()
            {
            isClosed = false;
            this.setString(null);
            new Thread(this).start();
            }
            public void cancelService()
            {
            isClosed = true;
            showInfo("服务终止");
            this.removeCommand(com_cancel);
            this.addCommand(com_pub);
            }
            /*
            * (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 == com_pub)
            {
            //发布service
            publish();
            } else if (arg0 == com_cancel)
            {
            cancelService();
            } else
            {
            cancelService();
            midlet.showMainMenu();
            }
            }
            /**
            * 内部类,服务端服务线程。
            * @author Jagie
            *
            * TODO To change the template for
            this generated type comment go to
            * Window - Preferences
            - Java - Code Style - Code Templates
            */
            private class ClientProcessor implements Runnable
            {
            private Thread processorThread;
            private Vector queue = new Vector();
            private boolean isOk = true;
            ClientProcessor() {
            processorThread = new Thread(this);
            processorThread.start();
            }
            public void run() {
            while (!isClosed) {
            synchronized (this) {
            if (queue.size() == 0)
            {
            try {
            //阻塞,直到有新客户连接
            wait();
            }
            catch (InterruptedException e)
            {
            }
            }
            }
            //处理连接队列
            StreamConnection conn;
            synchronized (this)
            {
            if (isClosed)
            {
            return;
            }
            conn = (StreamConnection)
            queue.firstElement();
            queue.removeElementAt(0);
            processConnection(conn);
            }
            }
            }
            /**
            * 往连接队列添加新连接,同时唤醒处理线程
            * @param conn
            */
            void addConnection(StreamConnection conn)
            {
            synchronized (this)
            {
            queue.addElement(conn);
            notify();
            }
            }
            }
            /**
            * 从StreamConnection读取输入
            * @param conn
            * @return
            */
            private String readInputString
            (StreamConnection conn)
            {
            String inputString = null;
            try {
            DataInputStream dis
            = conn.openDataInputStream();
            inputString = dis.readUTF();
            dis.close();
            } catch (Exception e)
            {
            e.printStackTrace();
            }
            return inputString;
            }
            /**
            * debug
            * @param s
            */
            private void showInfo(String s)
            {
            StringBuffer sb =
            new StringBuffer(this.getString());
            if (sb.length() > 0) {
            sb.append("\n");
            }
            sb.append(s);
            this.setString(sb.toString());
            }
            /**
            * 处理客户端连接
            * @param conn
            */
            private void processConnection
            (StreamConnection conn)
            {
            // 读取输入
            String inputString =
            readInputString(conn);
            //生成响应
            String outputString =
            inputString.toUpperCase();
            //输出响应
            sendOutputData(outputString, conn);
            try {
            conn.close();
            } catch (IOException e) {
            } // ignore
            showInfo("客户端输入:" +
            inputString + ",已成功响应!");
            }
            /**
            * 输出响应
            * @param outputData
            * @param conn
            */
            private void sendOutputData
            (String outputData, StreamConnection conn)
            {
            try
            {
            DataOutputStream dos =
            conn.openDataOutputStream();
            dos.writeUTF(outputData);
            dos.close();
            } catch (IOException e) {
            }
            }
            }

小结

本文给出了一个简单的蓝牙服务的例子。旨在帮助开发者快速掌握JSR82。希望本文能对你有所启发。

关闭本页
 
首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
Copyright ©2005-2008 chinaitpower.com All rights reserved. www.chinaitpower.com 版权所有