前提:

1. 使用真机测试

2. 测试前请蓝牙配对好手机与PC机蓝牙适配器(所以你需要一个蓝牙适配器插入PC USB口)

demo测试效果:

当手机左右摇摆时将数据传递到PC端,打印出来。(android重力感应)

PC服务端代码:

import java.io.IOException;import java.io.InputStream;import javax.microedition.io.Connector;import javax.microedition.io.StreamConnection;import javax.microedition.io.StreamConnectionNotifier;public class BTServer implements Runnable {// 流连接通知 用于创建流连接private StreamConnectionNotifier myPCConnNotifier = null;// 流连接private StreamConnection streamConn = null;// 接受数据字节流private byte[] acceptedByteArray = new byte[12];// 读取(输入)流private InputStream inputStream = null;/** * 主线程 *   * @param args */public static void main(String[] args) {new BTServer();}/** * 构造方法 */public BTServer() {try {// 得到流连接通知,下面的UUID必须和手机客户端的UUID相一致。myPCConnNotifier = (StreamConnectionNotifier) Connector.open("btspp://localhost:0000110100001000800000805F9B34FB");} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}// 打开连接通道并读取流线程new Thread(this).start();}@Overridepublic void run() {try {String inSTR = null;// 持续保持着监听客户端的连接请求while (true) {// 获取流连接streamConn = myPCConnNotifier.acceptAndOpen();// 获取流通道inputStream = streamConn.openInputStream();// 读取字节流while (inputStream.read(acceptedByteArray) != -1) {inSTR = new String(acceptedByteArray);System.out.println(inSTR);if (inSTR.contains("EXIT")) {// 手机客户端退出则关闭连接通道。inputStream.close();if (streamConn != null) {streamConn.close();} break;}  }}} catch (IOException e) {e.printStackTrace();}}}

服务端请导入bluecove.jar 和 commons-io.jar包

android手机客户端代码:

BlueTooth.java

package com.royal.bluetooth;import java.io.IOException;import java.io.OutputStream;import java.util.UUID;import android.app.Activity;import android.app.AlertDialog;import android.app.AlertDialog.Builder;import android.bluetooth.BluetoothAdapter;import android.bluetooth.BluetoothDevice;import android.bluetooth.BluetoothSocket;import android.content.DialogInterface;import android.content.Intent;import android.hardware.Sensor;import android.hardware.SensorEvent;import android.hardware.SensorEventListener;import android.hardware.SensorManager;import android.os.Bundle;import android.view.Gravity;import android.view.KeyEvent;import android.view.Window;import android.view.WindowManager;import android.widget.Toast;/** * BlueTooth & Sensor *  * @author royal *  */public class BlueTooth extends Activity {private static final int REQUEST_DISCOVERY = 0x1;// 建立蓝牙通信的UUID private static final UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");// 自带的蓝牙适配器private BluetoothAdapter bluetoothAdapter = null;// 扫描得到的蓝牙设备private BluetoothDevice device = null;// 蓝牙通信socketprivate BluetoothSocket btSocket = null;// 手机输出流private OutputStream outStream = null;private byte[] msgBuffer = null;// 传感器管理private SensorManager sensorMgr = null;// 传感器感应private Sensor sensor = null;// 手机x、y、z轴方向数据private int x, y, z;/** * 当这个activity第一次被创建的时候呼叫该方法 **/@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);/* 使程序窗口全屏 */// 创建一个没有title的全屏主题this.setTheme(android.R.style.Theme_NoTitleBar_Fullscreen);// 窗口全屏this.requestWindowFeature(Window.FEATURE_NO_TITLE);// 设置全屏标志this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);// 按bluetooth.xml文件布局风格setContentView(R.layout.bluetooth);// Gravity sensing 获取传感器sensorMgr = (SensorManager) this.getSystemService(SENSOR_SERVICE);sensor = sensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);// 获取手机默认上的蓝牙适配器bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();// 开启手机蓝牙设备bluetoothAction();// 查询附近所有的蓝牙设备并选择连接connectToDevice();}/** * 蓝牙开始 查询手机是否支持蓝牙,如果支持的话,进行下一步。 查看蓝牙设备是否已打开,如果否则打开。 */public void bluetoothAction() {// 查看手机是否有蓝牙设备功能if (hasAdapter(bluetoothAdapter)) {if (!bluetoothAdapter.isEnabled()) {// 开启蓝牙功能bluetoothAdapter.enable();}} else {// 程序终止this.finish();}}/** * 查看手机是否有蓝牙设备功能 *  * @param ba *            蓝牙设备适配器 * @return boolean */public boolean hasAdapter(BluetoothAdapter ba) {if (ba != null) {return true;}displayLongToast("该手机没有蓝牙功能!");return false;}/** * 创建一个长时间弹出的提示窗口toast *  * @param str *            提示字符串 */public void displayLongToast(String str) {Toast toast = Toast.makeText(this, str, Toast.LENGTH_LONG);toast.setGravity(Gravity.TOP, 0, 220);toast.show();}/** * 创建一个短时间弹出的提示窗口toast *  * @param str *            提示字符串 */public void displayShortToast(String str) {Toast toast = Toast.makeText(this, str, Toast.LENGTH_SHORT);toast.setGravity(Gravity.TOP, 0, 220);toast.show();}/** * 蓝牙若启动,则查询附近的所有蓝牙设备进行选择连接 */public void connectToDevice() {if (bluetoothAdapter.isEnabled()) {// 跳到另一个activity---DiscoveryActivity,该类用于查询附近所有的蓝牙设备。Intent intent = new Intent(this, DiscoveryActivity.class);// 弹出窗口提示displayLongToast("请选择一个蓝牙设备进行连接!");// 手机此时跳进DiscoveryActivity程序界面。// 注意:利用startActivityForResult回调数据返回当前的程序。// 详细参考:http://snmoney.blog.163.com/blog/static/440058201073025132670/this.startActivityForResult(intent, REQUEST_DISCOVERY);} else {this.finish();}}/** * startActivityForResult触发调用DiscoveryActivity后进行处理 * 获取到相应的蓝牙地址数据后,开始我们核心的数据交互 */@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {// TODO Auto-generated method stub// super.onActivityResult(requestCode, resultCode, data);// 这里确保相互回调时数据的准确传输if (requestCode != REQUEST_DISCOVERY) {return;}if (resultCode != RESULT_OK) {return;}// 获取到DiscoveryActivity点击项后传过来的蓝牙设备地址String addressStr = data.getStringExtra("address");// 根据蓝牙设备地址得到该蓝牙设备对象(这是扫描到的蓝牙设备哦,不是自己的)device = bluetoothAdapter.getRemoteDevice(addressStr);try {//根据UUID创建通信套接字btSocket = device.createRfcommSocketToServiceRecord(uuid);} catch (Exception e) {displayLongToast("通信通道创建失败!");}if (btSocket != null) {try {//这一步一定要确保连接上,不然的话程序就卡死在这里了。btSocket.connect();displayLongToast("通信通道连接成功!");} catch (IOException ioe) {displayLongToast("通信通道连接失败!");try {btSocket.close();displayLongToast("通信通道已关闭!");} catch (IOException ioe2) {displayLongToast("通信通道尚未连接,无法关闭!");}} try {// 获取输出流outStream = btSocket.getOutputStream();// 手机发出数据sendSensorData();} catch (IOException e) {displayLongToast("数据流创建失败!");} }}/** * 发送数据 发出从手机通过重力感应器获取到的数据 */public void sendSensorData() {// 重力感应监听SensorEventListener lsn = new SensorEventListener() {// 重写内部方法,当精确度发生变化是触发该方法。@Overridepublic void onAccuracyChanged(Sensor s, int accuracy) {// TODO Auto-generated method stub}// 重写内部方法,当数据发生变化的时候触发该方法。@Overridepublic void onSensorChanged(SensorEvent se) {// TODO Auto-generated method stub/** * 当手机横向头部朝左屏幕正对自己时 x=10,y=0,z=0; 当手机竖向屏幕正对自己时 x=0,y=10,z=0; * 当手机平放屏幕朝上时 x=0,y=0,z=10; 由此可知:当手握手机且竖向屏幕正对自己时,有: 水平就是X轴 * 垂直就是Y轴 屏幕所对方向便是Z轴 具体可参考简单例子---SensorDemo */x = (int)se.values[SensorManager.DATA_X];y = (int)se.values[SensorManager.DATA_Y];z = (int)se.values[SensorManager.DATA_Z];if (y > 5 || y < -5) {//String str = String.valueOf(x).concat(String.valueOf(y)).concat(String.valueOf(z));String str = "x" + String.valueOf(x) + "y" + String.valueOf(y) + "z" + String.valueOf(z) + "/";msgBuffer = str.getBytes();try {System.out.println("x=" + x + " y =" + y + " z =" + z);outStream.write(msgBuffer);} catch (IOException e) {displayShortToast("数据发送失败!");}}//if (y > 5 || y < -5) {//DataModel dataModel=new DataModel(x,y,z);//try {//System.out.println("x=" + x + " y =" + y + " z =" + z);//msgBuffer = dataModel.convertSelfToByteArray();//System.out.println("--------"+msgBuffer.length);//outStream.write(msgBuffer);//} catch (IOException e) {//Log.e("BlueTooth",e.getMessage());//e.printStackTrace();//displayShortToast("数据发送失败!");//}//}}};// 别忘了注册重力感应器,由于android的一些东东是又很大一部分都要这么干的。// 所有要注意。比如蓝牙这块,在对它打开的时候其实你也要注册权限的。看AndroidManifest.xml文件。sensorMgr.registerListener(lsn, sensor, SensorManager.SENSOR_DELAY_GAME);}// ////////////////////以下是退出程序的一些操作,不关核心功能的事//////////////////////////////////** * 重写方法:点击返回键,确认是否退出程序。 */@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {// TODO Auto-generated method stubif (keyCode == KeyEvent.KEYCODE_BACK) {Builder alertDialog = new AlertDialog.Builder(this);// 设置弹出框的图标alertDialog.setIcon(R.drawable.icon);// 设置弹出框的titlealertDialog.setTitle(R.string.prompt);// 设置弹出框的提示信息alertDialog.setMessage(R.string.quit);// 设置弹出框确认键触发事件alertDialog.setPositiveButton(R.string.confirm,new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog,int whichButton) {// TODO Auto-generated method stubtry {outStream.write("QUIT".getBytes());btSocket.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finish(); }});// 设置弹出框取消键触发事件(不做任何操作)alertDialog.setNegativeButton(R.string.cancel,new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {// TODO Auto-generated method stub}});// 显示弹出框alertDialog.show();return true;} else {// 如果点击的不是返回键按钮,那么该做什么操作就做什么操作。return super.onKeyDown(keyCode, event);}}/** * 重写方法:销毁线程,退出系统。 */@Overrideprotected void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();System.exit(0);}}

DiscoveryActivity.java

package com.royal.bluetooth;import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Set;import android.app.ListActivity;import android.bluetooth.BluetoothAdapter;import android.bluetooth.BluetoothDevice;import android.content.Intent;import android.os.Bundle;import android.view.View;import android.view.Window;import android.view.WindowManager;import android.widget.ListView;import android.widget.SimpleAdapter;/** * 该类集成ListActivity,主要是扫描并显示出附近所有的蓝牙设备 结果返回给BlueTooth *  * @author royal */public class DiscoveryActivity extends ListActivity {// 获取手机默认上的蓝牙适配器private BluetoothAdapter blueToothAdapter = BluetoothAdapter.getDefaultAdapter();// 把每一个HashMap键值对的蓝牙设备信息存放到list数组中并按文件布局风格的方式呈现出来private ArrayList<HashMap<String, String>> list = null;// 用于真正存放所有扫描到的蓝牙设备的listprivate List<BluetoothDevice> _devices = new ArrayList<BluetoothDevice>();@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);/* 使程序窗口全屏 */// 创建一个没有title的全屏主题this.setTheme(android.R.style.Theme_NoTitleBar_Fullscreen);// 窗口全屏this.requestWindowFeature(Window.FEATURE_NO_TITLE);// 设置全屏标志this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);// 按discovery.xml文件布局风格setContentView(R.layout.discovery);list = new ArrayList<HashMap<String, String>>();// 把扫描都的每一个蓝牙设备放到list中,并呈现给客户端showDevices();}/** * 把扫描都的每一个蓝牙设备放到list中,并呈现给客户端。 */public void showDevices() {// 获取所有已配对的蓝牙设备Set<BluetoothDevice> devices = blueToothAdapter.getBondedDevices();if (devices.size() > 0) {Iterator<BluetoothDevice> it = devices.iterator();BluetoothDevice bluetoothDevice = null;HashMap<String, String> map = new HashMap<String, String>();while (it.hasNext()) {bluetoothDevice = it.next();// 把每一个获取到的蓝牙设备的名称和地址存放到HashMap数组中,比如:xx:xx:xx:xx:xx: royalmap.put("address", bluetoothDevice.getAddress());map.put("name", bluetoothDevice.getName());// 该list用于存放呈现的蓝牙设备,存放的是每个设备的maplist.add(map);// 该list用于存放的是真正的每一个蓝牙设备对象_devices.add(bluetoothDevice);}// 构造一个简单的自定义布局风格,各个参数都有明确的相对应。具体给google一下SimpleAdapter和参考一些文献SimpleAdapter listAdapter = new SimpleAdapter(this, list,R.layout.device, new String[] { "address", "name" },new int[] { R.id.address, R.id.name });this.setListAdapter(listAdapter);}}/** * list点击项触发事件 当设备扫描显示完成后,可选择点击相应的设备进行连接。 */protected void onListItemClick(ListView l, View v, int position, long id) {Intent result = new Intent();String addressStr = _devices.get(position).getAddress();//地址只取到17位,虽然addressStr和address都一样 xx:xx:xx:xx:xx:xxString address = addressStr.substring(addressStr.length() - 17);result.putExtra("address", address);// 这个就是回传数据了,将地址传回给BlueTooth---activity// 这里的resultCode是RESULT_OK,BlueTooth---activity方法onActivityResult里对应的resultCode也应该是RESULT_OK//只有resultCode值相匹配,才能确保result数据回调不出错。setResult(RESULT_OK, result);// 一定要finish,只有finish后才能将数据传给BlueTooth---activity// 并在onActivityResult做处理finish();}}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"      package="com.royal.bluetooth"      android:versionCode="1"      android:versionName="1.0">    <application android:icon="@drawable/icon" android:label="@string/app_name">            <activity android:name=".BlueTooth"                  android:label="@string/app_name"                   android:screenOrientation="landscape">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>                <activity android:name=".DiscoveryActivity"          android:screenOrientation="landscape">        <intent-filter>        <action android:name="android.intent.action.MAIN"/>        <category android:name="android.intent.category.DEFAULT"/>        </intent-filter>        </activity>    </application>        <!-- 打开和关闭蓝牙部分的权限 -->    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>    <uses-permission android:name="android.permission.BLUETOOTH"/>        <uses-sdk android:minSdkVersion="7" /></manifest> 

布局:

bluetooth.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    ><TextView android:layout_width="fill_parent"     android:layout_height="wrap_content" android:id="@+id/sensor"/></LinearLayout>

device.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="horizontal"    android:paddingBottom="1dip"    android:paddingLeft="10dip"    android:paddingRight="10dip"    android:paddingTop="1dip" >    <TextView        android:id="@+id/address"        android:layout_width="180dip"        android:layout_height="30dip"        android:singleLine="true"        android:textSize="10pt" />    <TextView        android:id="@+id/name"        android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:gravity="right"        android:textSize="10pt" /></LinearLayout>

discovery.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent" android:layout_height="fill_parent"><LinearLayoutandroid:id="@+id/listLinearLayout"android:layout_width="fill_parent"android:layout_height="wrap_content"android:orientation="vertical"><ListViewandroid:id="@id/android:list"android:layout_width="fill_parent"android:layout_height="wrap_content"android:drawSelectorOnTop="false"android:scrollbars="vertical"/></LinearLayout></LinearLayout>

更多相关文章

  1. 查看Android设备Mem命令
  2. Android(安卓)6.0 中新的新技术
  3. USB Host and Accessory
  4. android在PC端键盘启动手机上的应用的摸索
  5. 手机拨号启动隐藏程序
  6. cocos2dx实现获得设备的网络连接状态
  7. Android源码中常用的系统广播
  8. delphi xe5 android 开发实现手机打电话和发短信
  9. Android(安卓)Dialog设置TYPE_SYSTEM_ALERT 小米,魅族手机不能显

随机推荐

  1. Android中隐式意图(Intent)用法
  2. 程序媛也话Android(安卓)之 自定义控件(垂
  3. Android系统目录/system/etc下自建文件存
  4. John Gruber:iPhone 改变了 Android(安卓)
  5. AsyncTask 完全解析
  6. Android(安卓)最简单的导航栏实现
  7. InputFilter实现EditText文本输入过滤器
  8. AndroidLinker与SO加壳技术
  9. ADB 常用命令
  10. 【Android(安卓)UI】如何做一个纯粹的And