手机蓝牙串口的调试助手demo实现

在开始学Android开发的时候,由于其他的需要,本着学习的心态,再网上找了一个资源,做了一个手机蓝牙串口的调试助手。

程序搭建原理简介:

在Android蓝牙通信连接的开发中,需要在AndroidManifest.xml配置文件中增加相应的权限,需要添加BLUETOOTH和BLUETOOTH_ADMIN这两个权限。在确保手机支持蓝牙的前提下,应用程序通过获取BluetoothAdapter类,根据其getDefaultAdapter()方法获取该类的实例,通过.isEnabled()查询手机蓝牙是否为打开状态。通过BluetoothAdapter.getBondedDevices()获取该手机蓝牙设备已经匹配的蓝牙设备信息;搜索新设备可通过使用BluetoothAdapter.startDiscovery()方法进入一个为时12秒的扫描发现外围蓝牙其他设备,当发系统现设备时,随即系统发出广播,程序通过注册并接受该广播,获取该广播信息里的蓝牙设备BluetoothDevice实例,从而获取该蓝牙设备的信息。

蓝牙通信技术可以在短距离传输中以无线电的方式传递数据,借助蓝牙通信技术来创造便利性,智能性和可控性[8]。实现Android应用程序与蓝牙设备连接,类似TCP连接,构建Android蓝牙通信连接两个关键类是BluetoothSocketBluetoothServerSocket[9]

在Android蓝牙通信连接的开发中,实现基本功能蓝牙通信软件,则需要在软件实现服务端和客户端两种机制[10]。这种通信构建需要在服务端程序根据UUID(通用唯一识别码)调用listenUsingRfcommWithServiceRecord(String,UUID)获得BluetoothServerSocket对象,在子线程调用accept()方法开启监听线程。在客户端也根据UUID(通用唯一识别码)调用createRfcommSocketToServiceRecord(UUID)获取BluetoothSocket,在子线程调用connect()方法发起请求连接。

构建蓝牙通信连接后,不管是服务器还是客户端机制,彼此都会连接好的BluetoothSocket对象,获取对应的输入字节流(inputstream)和输出字节流(outputstream),可调用它们的read(byte[])和write(byte[])方法来分别实现对数据流的读和写,实现蓝牙数据通信功能。

程序蓝牙通信搭建原理框图:


本项目所用的权限:

   由于用到蓝牙连接,Android存储权限获取,要配置相应的权限,没有配置Android6.0动态权限获取。

<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />

接下来大体过一下代码,代码 基本都有注释,基本应该都能看的懂,由于时间原因就不一一介绍了:

构建蓝牙的基本服务类BluetoothChatService.class

/**
 * 这个类做了所有设置和管理与其它蓝牙设备连接的工作。
 *  它有一个线程监听传入连接,一个线程与设备进行连接,还有一个线程负责连接后的数据传输。
 *
 */
public class BluetoothChatService {
    // Debugging
    private static final String TAG = "BluetoothChatService";
    private static final boolean D = true;
    // 创建服务器套接字时SDP记录的名称
    private static final String NAME = "BluetoothChat";
    // 该应用的唯一UUID
    private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
    // 成员变量
    private final BluetoothAdapter mAdapter;
    private final Handler mHandler;
    private AcceptThread mAcceptThread;
    private ConnectThread mConnectThread;
    private ConnectedThread mConnectedThread;
    private int mState;
    // 指示当前连接状态的常量
    public static final int STATE_NONE = 0;       // we're doing nothing
    public static final int STATE_LISTEN = 1;     // 现在正在侦听传入连接
    public static final int STATE_CONNECTING = 2; // 现在启动传出连接
    public static final int STATE_CONNECTED = 3;  // 现在连接到远程设备

    //蓝牙接收延迟时间
     private int delay_time;
    public void setDelay_time(int delay_time) {
        this.delay_time = delay_time;
    }
    /**
     * 构造函数。 准备新的BluetoothChat会话。
     * @param context  The UI Activity Context
     * @param handler  A Handler to send messages back to the UI Activity
     */
    public BluetoothChatService(Context context, Handler handler) {
        mAdapter = BluetoothAdapter.getDefaultAdapter();
        mState = STATE_NONE;
        mHandler = handler;
        delay_time=100;
    }

    /**
     * 设置聊天连接的当前状态
     * @param state  定义当前连接状态的整数
     */
    private synchronized void setState(int state) {
        if (D) Log.d(TAG, "setState() " + mState + " -> " + state);
        mState = state;

        // Give the new state to the Handler so the UI Activity can update
        mHandler.obtainMessage(BluetoothChat.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
    }

    /**
     * 返回当前连接状态。 */
    public synchronized int getState() {
        return mState;
    }

    /**
     * 启动聊天服务。 特别地启动AcceptThread以在侦听(服务器)模式下开始会话。
     * Activity onResume()调用 */
    public synchronized void start() {
        if (D) Log.d(TAG, "start");

        // 取消尝试建立连接的任何线程
        if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}

        // 取消当前运行连接的任何线程
        if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}

        // 启动线程以监听BluetoothServerSocket
        if (mAcceptThread == null) {
            mAcceptThread = new AcceptThread();
            mAcceptThread.start();
        }
        setState(STATE_LISTEN);
    }

    /**
     * 启动ConnectThread以启动与远程设备的连接。
     * @param device  要连接的BluetoothDevice
     */
    public synchronized void connect(BluetoothDevice device) {
        if (D) Log.d(TAG, "connect to: " + device);

        // 取消尝试建立连接的任何线程
        if (mState == STATE_CONNECTING) {
            if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
        }

        // 取消当前运行连接的任何线程
        if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}

        // 启动线程以与给定设备连接
        mConnectThread = new ConnectThread(device);
        mConnectThread.start();
        setState(STATE_CONNECTING);
    }

    /**
     * 启动ConnectedThread以开始管理蓝牙连接
     * @param socket  在其上进行连接的BluetoothSocket
     * @param device  已连接的BluetoothDevice
     */
    public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
        if (D) Log.d(TAG, "connected");

        // 取消完成连接的线程
        if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}

        // 取消当前运行连接的任何线程
        if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}

        // 取消接受线程,因为我们只想连接到一个设备
        if (mAcceptThread != null) {mAcceptThread.cancel(); mAcceptThread = null;}

        // 启动线程以管理连接并执行传输
        mConnectedThread = new ConnectedThread(socket);
        mConnectedThread.start();

        //将连接的设备的名称发送回UI活动
        Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_DEVICE_NAME);
        Bundle bundle = new Bundle();
        bundle.putString(BluetoothChat.DEVICE_NAME, device.getName());
        msg.setData(bundle);
        mHandler.sendMessage(msg);

        setState(STATE_CONNECTED);
    }

    /**
     * Stop all threads
     */
    public synchronized void stop() {
        if (D) Log.d(TAG, "stop");
        if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
        if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
        if (mAcceptThread != null) {mAcceptThread.cancel(); mAcceptThread = null;}
        setState(STATE_NONE);
    }

    /**
     * 以线程锁(不同步)方式写入ConnectedThread
     * @param out 要写入的字节
     * @see ConnectedThread#write(byte[])
     */
    public void write(byte[] out) {
        //创建临时对象
        ConnectedThread r;
        // 同步ConnectedThread的副本
        synchronized (this) {
            if (mState != STATE_CONNECTED) return;
            r = mConnectedThread;
        }
        //执行写入不同步
        r.write(out);
    }

    /**
     * 指示连接尝试失败并通知UI活动.
     */
    private void connectionFailed() {
        setState(STATE_LISTEN);

        // 将失败消息发送回活动
        Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST);
        Bundle bundle = new Bundle();
        bundle.putString(BluetoothChat.TOAST, "无法连接设备");
        msg.setData(bundle);
        mHandler.sendMessage(msg);
    }

    /**
     * 指示连接已丢失并通知UI活动
     */
    private void connectionLost() {
        setState(STATE_LISTEN);

        // 将失败消息发送回活动
        Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST);
        Bundle bundle = new Bundle();
        bundle.putString(BluetoothChat.TOAST, "丢失设备连接");
        msg.setData(bundle);
        mHandler.sendMessage(msg);
    }

    /**
     * 此线程在侦听传入连接时运行。 它的行为像一个服务器端。
     *  它运行直到接受连接
     * (或直到取消).
     */
    private class AcceptThread extends Thread {
        // 本地服务器套接字
        private final BluetoothServerSocket mmServerSocket;

        public AcceptThread() {
            BluetoothServerSocket tmp = null;

            // 创建一个新的侦听服务器套接字
            try {
                tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
            } catch (IOException e) {
                Log.e(TAG, "listen() failed", e);
            }
            mmServerSocket = tmp;
        }

        public void run() {
            if (D) Log.d(TAG, "BEGIN mAcceptThread" + this);
            setName("AcceptThread");
            BluetoothSocket socket = null;

            // 如果我们没有连接,请监听服务器插座
            while (mState != STATE_CONNECTED) {
                try {
                    // 这是一个阻塞调用,只会在成功的连接或异常返回
                    socket = mmServerSocket.accept();
                } catch (IOException e) {
                    Log.e(TAG, "accept() failed", e);
                    break;
                }

                // 如果连接被接受
                if (socket != null) {
                    synchronized (BluetoothChatService.this) {
                        switch (mState) {
                        case STATE_LISTEN:
                        case STATE_CONNECTING:
                            // 状况正常。 启动连接的线程。
                            connected(socket, socket.getRemoteDevice());
                            break;
                        case STATE_NONE:
                        case STATE_CONNECTED:
                            //未准备就绪或已连接。 终止新套接字。
                            try {
                                socket.close();
                            } catch (IOException e) {
                                Log.e(TAG, "Could not close unwanted socket", e);
                            }
                            break;
                        }
                    }
                }
            }
            if (D) Log.i(TAG, "END mAcceptThread");
        }

        public void cancel() {
            if (D) Log.d(TAG, "cancel " + this);
            try {
                mmServerSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "close() of server failed", e);
            }
        }
    }

    /**
     * 尝试与设备建立传出连接时,此线程运行。类似于一个客户端
     * 它直通; 连接
     * 成功或失败。
     */
    private class ConnectThread extends Thread {
        private final BluetoothSocket mmSocket;
        private final BluetoothDevice mmDevice;

        public ConnectThread(BluetoothDevice device) {
            mmDevice = device;
            BluetoothSocket tmp = null;

            // 获取与给定的蓝牙设备的连接的BluetoothSocket
            try {
                tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
            } catch (IOException e) {
                Log.e(TAG, "create() failed", e);
            }
            mmSocket = tmp;
        }

        public void run() {
            Log.i(TAG, "BEGIN mConnectThread");
            setName("ConnectThread");
            // 始终取消发现,因为它会减慢连接速度
            mAdapter.cancelDiscovery();
            //连接到BluetoothSocket
            try {
                // 这是一个阻塞调用,只会在成功的连接或异常返回
                mmSocket.connect();
            } catch (IOException e) {
                connectionFailed();
                // Close the socket
                try {
                    mmSocket.close();
                } catch (IOException e2) {
                    Log.e(TAG, "unable to close() socket during connection failure", e2);
                }
                // 启动服务以重新启动侦听模式
                BluetoothChatService.this.start();
                return;
            }

            // 重置ConnectThread,因为我们完成了
            synchronized (BluetoothChatService.this) {
                mConnectThread = null;
            }

            // 启动连接的线程
            connected(mmSocket, mmDevice);
        }

        public void cancel() {
            try {
                mmSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "close() of connect socket failed", e);
            }
        }
    }

    /**
     * 此线程在与远程设备的连接期间运行。
     * 它处理所有传入和传出传输。
     */
    private class ConnectedThread extends Thread {
        private final BluetoothSocket mmSocket;
        private final InputStream mmInStream;
        private final OutputStream mmOutStream;

        public ConnectedThread(BluetoothSocket socket) {
            Log.d(TAG, "create ConnectedThread");
            mmSocket = socket;
            InputStream tmpIn = null;
            OutputStream tmpOut = null;

            // 获取BluetoothSocket输入和输出流
            try {
                tmpIn = socket.getInputStream();
                tmpOut = socket.getOutputStream();
            } catch (IOException e) {
                Log.e(TAG, "temp sockets not created", e);
            }

            mmInStream = tmpIn;
            mmOutStream = tmpOut;
        }

        public void run()
        {
            Log.i(TAG, "BEGIN mConnectedThread");
            byte[] buffer = new byte[1024];  
            int bytes;  
              
            while (true) {  
                try {  
                        while(mmInStream.available()==0){
                    }  
                    try {  
                        Thread.sleep(delay_time);  //当有数据流入时,线程休眠一段时间,默认100ms
                    } catch (InterruptedException e) {  
                        e.printStackTrace();  
                    }  
                    bytes = mmInStream.read(buffer);  //从字节流中读取数据填充到字节数组,返回读取数据的长度
                    mHandler.obtainMessage(BluetoothChat.MESSAGE_READ, bytes, -1, buffer)
                            .sendToTarget();  //将消息传回主界面
                } catch (IOException e) {  
                    Log.e(TAG, "disconnected", e);  
                    connectionLost();  
                    break;  
                }  
             }
        }

        /**
         * 写入连接的OutStream         * @param buffer  The bytes to write
         */
        public void write(byte[] buffer) {
            try {
                mmOutStream.write(buffer);

                //将发送的消息共享回UI活动
                mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer)
                        .sendToTarget();
            } catch (IOException e) {
                Log.e(TAG, "Exception during write", e);
            }
        }

        public void cancel() {
            try {
                mmSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "close() of connect socket failed", e);
            }
        }
    }
}

主要显示视图UI类 BluetoothChat.class类

/**
 * 显示通信信息的主Activity */
public class BluetoothChat extends Activity {
   // Debugging
   private static final String TAG = "BluetoothChat";
   private static final boolean D = true;
    //返回页面标志
   private boolean exit =false;

   // 来自BluetoothChatService Handler的消息类型
   public static final int MESSAGE_STATE_CHANGE = 1;
   public static final int MESSAGE_READ = 2;
   public static final int MESSAGE_WRITE = 3;
   public static final int MESSAGE_DEVICE_NAME = 4;
   public static final int MESSAGE_TOAST = 5;

   // 来自BluetoothChatService Handler的关键名
   public static final String DEVICE_NAME = "device_name";
   public static final String TOAST = "toast";
   // Intent请求代码
   private static final int REQUEST_CONNECT_DEVICE = 1;
   private static final int REQUEST_ENABLE_BT = 2;

   // 布局视图
   private TextView mTitle;
   private TextView mConversationView;
   private TextView outcount;
   private TextView incount;

   private TextView view;


   // 声明复选按钮
   private CheckBox in16;
   private CheckBox autosend;
   private CheckBox out16;

   // 声明button按钮
   private Button mSendButton;

   private Button search;
   private Button disc;
   // 用来保存存储的文件名
   public String filename = "";
   // 保存用数据缓存
   private String fmsg = "";
   // 计数用
   private int countin = 0;
   private int countout = 0;

   // 已连接设备的名称
   private String mConnectedDeviceName = null;
   // 输出流缓冲区
   private StringBuffer mOutStringBuffer;

   // 本地蓝牙适配器
   private BluetoothAdapter mBluetoothAdapter = null;
   // 用于通信的服务
   private BluetoothChatService mChatService = null;
   // CheckBox   private boolean inhex = true;
   private boolean outhex = true;
   private boolean auto = false;


   @Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      if (D)
         Log.e(TAG, "+++ ON CREATE +++");
      // 设置窗口布局
      requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
      setContentView(R.layout.activity_bluetooth_chat_layout);
      getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,
            R.layout.custom_title);

      //布局控件初始化函数,注册相关监听器
      init();

      // 获取本地蓝牙适配器
      mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

      // 如果没有蓝牙适配器,则不支持
      if (mBluetoothAdapter == null) {
         Toast.makeText(this, "蓝牙不可用", Toast.LENGTH_LONG).show();
         finish();
         return;
      }

      search.setOnClickListener(new OnClickListener() {

         @Override
         public void onClick(View v) {
            search();
         }
      });

      disc.setOnClickListener(new OnClickListener() {

         @Override
         public void onClick(View v) {
            Toast.makeText(BluetoothChat.this, "该设备已设置为可在300秒内发现,且可连接",
                  Toast.LENGTH_SHORT).show();
            ensureDiscoverable();
         }
      });
   }

   public void search(){
      Intent serverIntent = new Intent(BluetoothChat.this,
            device.class);
      startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
   }

   private void init(){
      // 通过findViewById获得CheckBox对象
      in16 = (CheckBox) findViewById(R.id.in16);
      autosend = (CheckBox) findViewById(R.id.autosend);
      out16 = (CheckBox) findViewById(R.id.out16);

      // 注册事件监听器
      in16.setOnCheckedChangeListener(listener);
      autosend.setOnCheckedChangeListener(listener);
      out16.setOnCheckedChangeListener(listener);
      // 获得button的对象
      search = (Button) findViewById(R.id.search);
      disc = (Button) findViewById(R.id.discoverable1);

      mSendButton = (Button) findViewById(R.id.button_send);
      //获取选择控件的值

      // 设置custom title
      mTitle = (TextView) findViewById(R.id.title_left_text);
      mTitle.setText(R.string.activity_name);
      mTitle = (TextView) findViewById(R.id.title_right_text);
      view = (TextView) findViewById(R.id.edit_text_out);

   }


      // 响应事件监听
   private OnCheckedChangeListener listener = new OnCheckedChangeListener() {

         @Override
      public void onCheckedChanged(CompoundButton buttonView,
            boolean isChecked) {
         // in16被选中
         if (buttonView.getId() == R.id.in16) {
            if (isChecked) {
               Toast.makeText(BluetoothChat.this, "16进制显示",
                     Toast.LENGTH_SHORT).show();
               inhex = true;
            } else
               inhex = false;
         }

         //out16选中
         if (buttonView.getId() == R.id.out16) {
            if (isChecked) {
               Toast.makeText(BluetoothChat.this, "16进制发送",
                     Toast.LENGTH_SHORT).show();
               outhex = true;
            } else
               outhex = false;
         }
         // 自动发送被选中
         if (buttonView.getId() == R.id.autosend) {
            if (isChecked) {
               Toast.makeText(BluetoothChat.this, "自动发送",
                     Toast.LENGTH_SHORT).show();
               auto = true;
            } else
               auto = false;
         }
      }
   };


   @Override
   public void onStart() {
      super.onStart();
      if (D)
         Log.e(TAG, "++ ON START ++");


      //如果BT未打开,请求启用。
      // 然后在onActivityResult期间调用setupChat()
      if (!mBluetoothAdapter.isEnabled())
      {
         Intent enableIntent = new Intent(
               BluetoothAdapter.ACTION_REQUEST_ENABLE);
         startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
         // 否则,设置聊天会话
      }
      else
      {

         if (mChatService == null)
            setupChat();
         else {
            try {
               mChatService.wait(100);
            } catch (InterruptedException e) {
               e.printStackTrace();
            }
         }
      }
   }


   //300秒内搜索
   private void ensureDiscoverable() {
      if (D)
         Log.d(TAG, "ensure discoverable");
      if (mBluetoothAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
         Intent discoverableIntent = new Intent(
               BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
         //设置本机蓝牙可让发现
         discoverableIntent.putExtra(
               BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
         startActivity(discoverableIntent);
      }
   }

   //自动发送
   private Runnable runnable = new Runnable() {
      @Override
      public void run() {
         String message = view.getText().toString();
         sendMessage(message);
         // 初始化输出流缓冲区
         mOutStringBuffer = new StringBuffer("");

      }
   };


//初始化
   private void setupChat() {
      Log.d(TAG, "setupChat()");

      mConversationView = (TextView) findViewById(R.id.in);
      mConversationView.setMovementMethod(ScrollingMovementMethod
            .getInstance());// 使TextView接收区可以滚动
      outcount = (TextView) findViewById(R.id.outcount);
      incount = (TextView) findViewById(R.id.incount);
      outcount.setText("0");
      incount.setText("0");

      mSendButton.setOnClickListener(new OnClickListener() {
         public void onClick(View v) {
            // 使用编辑文本小部件的内容发送消息
            TextView view = (TextView) findViewById(R.id.edit_text_out);

               String message = view.getText().toString();
               sendMessage(message);

         }
      });

         // 初始化BluetoothChatService以执行app_incon_bluetooth连接
      mChatService = new BluetoothChatService(this, mHandler);

      //初始化外发消息的缓冲区
      mOutStringBuffer = new StringBuffer("");
   }


   //重写发送函数,参数不同。
   private void sendMessage(String message) {
      // 确保已连接
      if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) {
         Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT)
               .show();
         return;
      }
      // 检测是否有字符串发送
      if (message.length() > 0) {
         // 获取 字符串并告诉BluetoothChatService发送
         if (outhex == true) {
            byte[] send = Data_syn.hexStr2Bytes(message);
            mChatService.write(send);//回调service

         } else if (outhex == false) {
            byte[] send = message.getBytes();
            mChatService.write(send);//回调service
         }
         // 清空输出缓冲区
         mOutStringBuffer.setLength(0);
      }
      else {
         Toast.makeText(this,"发送内容不能为空",
               Toast.LENGTH_SHORT).show();
      }
   }





   // HandlerBluetoothChatService中获取信息
   private final Handler mHandler = new Handler() {
      @Override
      public void handleMessage(Message msg) {
         switch (msg.what) {
            case MESSAGE_STATE_CHANGE:
               if (D)
               Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);


               switch (msg.arg1)
               {
                  case BluetoothChatService.STATE_CONNECTED:
                    mTitle.setText(R.string.title_connected_to);
                    mTitle.append(mConnectedDeviceName);
                    mConversationView.setText(null);
                    break;

                  case BluetoothChatService.STATE_CONNECTING:
                   mTitle.setText(R.string.title_connecting);
                   break;

                  case BluetoothChatService.STATE_LISTEN:
                  case BluetoothChatService.STATE_NONE:
                   mTitle.setText(R.string.title_not_connected);
                   break;
               }
            break;

         case MESSAGE_WRITE:
            byte[] writeBuf = (byte[]) msg.obj;
            // 自动发送
            if (auto == true) {

                  // 自动发送模块
               mHandler.postDelayed(runnable, 1000);
               } else if (auto == false) {
                  mHandler.removeCallbacks(runnable);
            }
            // 发送计数
            if (outhex == true) {
               String writeMessage = Data_syn.Bytes2HexString(writeBuf);
               countout += writeMessage.length() / 2;
               outcount.setText("" + countout);
            } else if (outhex == false) {
               String writeMessage = null;
               try {
                  writeMessage = new String(writeBuf, "GBK");
               } catch (UnsupportedEncodingException e1) {
                  e1.printStackTrace();
               }
               countout += writeMessage.length();
               outcount.setText("" + countout);
            }
            break;
         case MESSAGE_READ:

            byte[] readBuf = (byte[]) msg.obj;

              //检错误码计算函数

            if (inhex == true) {
               String readMessage = " "
                     + Data_syn.bytesToHexString(readBuf, msg.arg1);
               fmsg += readMessage;
               mConversationView.append(readMessage);
               // 接收计数,更显UI
               countin += readMessage.length() / 2;
               incount.setText("" + countin);
            } else if (inhex == false) {
               String readMessage = null;
               try {
                  readMessage = new String(readBuf, 0, msg.arg1, "GBK");
               } catch (UnsupportedEncodingException e) {
                  e.printStackTrace();
               }
               fmsg += readMessage;
               mConversationView.append(readMessage);
               // 接收计数,更新UI
               countin += readMessage.length();
               incount.setText("" + countin);
            }
            break;
         case MESSAGE_DEVICE_NAME:
            // 保存已连接设备的名称
            mConnectedDeviceName = msg.getData().getString(DEVICE_NAME);
            Toast.makeText(getApplicationContext(),
                  "连接到 " + mConnectedDeviceName, Toast.LENGTH_SHORT)
                  .show();
            break;
         case MESSAGE_TOAST:
            Toast.makeText(getApplicationContext(),
                  msg.getData().getString(TOAST), Toast.LENGTH_SHORT)
                  .show();
            break;
         }
      }
   };



    //返回该Activity回调函数
   public void onActivityResult(int requestCode, int resultCode, Intent data) {
      if (D)
         Log.d(TAG, "onActivityResult " + resultCode);

      switch (requestCode) {

//search返回的
      case REQUEST_CONNECT_DEVICE:

         // DeviceListActivity返回时要连接的设备
         if (resultCode == Activity.RESULT_OK) {
            // 获取设备的MAC地址
            String address = data.getExtras().getString(
                  device.EXTRA_DEVICE_ADDRESS);

            // 获取BLuetoothDevice对象
            BluetoothDevice device = mBluetoothAdapter
                  .getRemoteDevice(address);
            // 尝试连接到设备
            mChatService.connect(device);
         }
         break;
//start返回的(遇到蓝牙不可用退出)
      case REQUEST_ENABLE_BT:
         // 当启用蓝牙的请求返回时
         if (resultCode == Activity.RESULT_OK)
         {
            //蓝牙已启用,因此设置聊天会话
            setupChat();//初始化文本
         }
         else
         {
            // 用户未启用蓝牙或发生错误
            Log.d(TAG, "BT not enabled");

            Toast.makeText(this, R.string.bt_not_enabled_leaving,
                  Toast.LENGTH_SHORT).show();
            finish();
         }
      }
   }


   // 保存按键响应函数
   public void onSaveButtonClicked(View v) {
      Save();
   }

   // 清屏按键响应函数
   public void onClearButtonClicked(View v) {
      fmsg = "";
      mConversationView.setText(null);
      view.setText(null);
      return;
   }

   // 清除计数按键响应函数
   public void onClearCountButtonClicked(View v) {
      countin = 0;
      countout = 0;
      outcount.setText("0");
      incount.setText("0");
      return;
   }



   // 保存功能实现
   private void Save() {
      // 显示对话框输入文件名
      LayoutInflater factory = LayoutInflater.from(BluetoothChat.this); // 图层模板生成器句柄
      final View DialogView = factory.inflate(R.layout.sname, null); // sname.xml模板生成视图模板
      new AlertDialog.Builder(BluetoothChat.this).setTitle("文件名")
            .setView(DialogView) // 设置视图模板
            .setPositiveButton("确定", new DialogInterface.OnClickListener() // 确定按键响应函数
                  {
                     public void onClick(DialogInterface dialog,
                           int whichButton) {
                        EditText text1 = (EditText) DialogView
                              .findViewById(R.id.sname); // 得到文件名输入框句柄
                        filename = text1.getText().toString(); // 得到文件名

                        try {
                           if (Environment.getExternalStorageState()
                                 .equals(Environment.MEDIA_MOUNTED)) { // 如果SD卡已准备好

                              filename = filename + ".txt"; // 在文件名末尾加上.txt
                              File sdCardDir = Environment
                                    .getExternalStorageDirectory(); // 得到SD卡根目录
                              File BuildDir = new File(sdCardDir,
                                    "/BluetoothSave"); // 打开BluetoothSave目录,如不存在则生成
                              if (BuildDir.exists() == false)
                                 BuildDir.mkdirs();
                              File saveFile = new File(BuildDir,
                                    filename); // 新建文件句柄,如已存在仍新建文档
                              FileOutputStream stream = new FileOutputStream(
                                    saveFile); // 打开文件输入流
                              stream.write(fmsg.getBytes());
                              stream.close();
                              Toast.makeText(BluetoothChat.this,
                                    "存储成功!", Toast.LENGTH_SHORT)
                                    .show();
                           } else {
                              Toast.makeText(BluetoothChat.this,
                                    "没有存储卡!", Toast.LENGTH_LONG)
                                    .show();
                           }
                        } catch (IOException e) {
                           return;
                        }
                     }
                  })
            .setNegativeButton("取消", // 取消按键响应函数,直接退出对话框不做任何处理
                  new DialogInterface.OnClickListener() {
                     public void onClick(DialogInterface dialog,
                           int which) {
                     }
                  }).show(); // 显示对话框
   }

   @Override
   public synchronized void onResume() {
      super.onResume();
      if (D)
         Log.e(TAG, "+ ON RESUME +");
      // onResume()中执行此检查包括在onStart()期间未启用BT的情况,
      // 因此我们暂停启用它...
      // onResume()将在ACTION_REQUEST_ENABLE活动时被调用返回.
      if (mChatService != null) {
         // 只有状态是STATE_NONE,我们知道我们还没有启动蓝牙
         if (mChatService.getState() == BluetoothChatService.STATE_NONE) {
            // 启动BluetoothChat服务
            mChatService.start();
         }
      }

   }

   @Override
   public synchronized void onPause() {
      super.onPause();
      if (D)
         Log.e(TAG, "- ON PAUSE -");
   }

   @Override
   public void onStop() {
      super.onStop();
      if (D)
         Log.e(TAG, "-- ON STOP --");
   }


   @Override
   public void onDestroy() {
      super.onDestroy();
      // 停止蓝牙通信连接服务
      if (mChatService != null)
         mChatService.stop();
      if (D)
         Log.e(TAG, "--- ON DESTROY ---");
   }
   @Override
   public void onBackPressed()
   {
      exit();
   }

   public void exit()
   {
      exit = true;


      if(exit  ==  true)
      {
         this.finish();
      }

   }
}

DeviceListActivity.class,蓝牙配对列表显示,点击返回给主界面,主要为一个listview

/**
 * 这个 Activity显示为一个对话框. 它列出了所有已配对的设备和之后在该地区搜索到的设备. 当一个设备被用户选择后,
 * 该设备的MAC地址会在result Intent中被传回到父 Activity.
 */
public class DeviceListActivity extends Activity
{
   // Debugging
   private static final String TAG = "DeviceListActivity";
   private static final boolean D = true;

   // Return Intent extra
   public static String EXTRA_DEVICE_ADDRESS = "device_address";
   public static String EXTRA_LEGAL = "legal";

   // Member fields
   private BluetoothAdapter mBtAdapter;
   private ArrayAdapter<String> mPairedDevicesArrayAdapter;
   private ArrayAdapter<String> mNewDevicesArrayAdapter;

   private boolean isexist =false;
   //自动配对结果
   private boolean result=false;



   @Override
   protected void onCreate(Bundle savedInstanceState)
   {
      super.onCreate(savedInstanceState);

      // 设置窗口
      requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
      setContentView(R.layout.device_list);

      // 设置结果CANCELED使用户退出
      setResult(Activity.RESULT_CANCELED);


      // 初始化阵列适配器。 一个用于已配对的设备,一个用于新发现的设备,一个用于测试专用的设备
      mPairedDevicesArrayAdapter = new ArrayAdapter<String>(this,
            R.layout.device_name);
      mNewDevicesArrayAdapter = new ArrayAdapter<String>(this,
            R.layout.device_name);


      // 为配对的设备查找和设置ListView
      ListView pairedListView = (ListView) findViewById(R.id.paired_devices);

      pairedListView.setAdapter(mPairedDevicesArrayAdapter);
      pairedListView.setOnItemClickListener(mDeviceClickListener);


      // 为新发现的设备找到并设置ListView
      ListView newDevicesListView = (ListView) findViewById(R.id.new_devices);

      newDevicesListView.setAdapter(mNewDevicesArrayAdapter);
      newDevicesListView.setOnItemClickListener(mDeviceClickListener);



      // 发现设备时注册广播
      IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
      this.registerReceiver(mReceiver, filter);

      // 发现完成后注册广播
      filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
      this.registerReceiver(mReceiver, filter);

      //自动配对请求注册广播

      filter = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST);
      this.registerReceiver(mReceiver, filter);

      // 获取本地蓝牙适配器
      mBtAdapter = BluetoothAdapter.getDefaultAdapter();

      // 获取一组当前配对的设备
      Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();

      // 如果有配对的设备,请将每个设备添加到ArrayAdapter
      TextView textView = (TextView) findViewById(R.id.title_paired_devices);
      if (pairedDevices.size() > 0)
      {
           textView.setVisibility(View.VISIBLE);
         for (BluetoothDevice device : pairedDevices)
         {   isexist=true;
            mPairedDevicesArrayAdapter.add(device.getName() + "\n"
                  + device.getAddress());

         }
      }

      if (isexist==false)
      {
         textView.setVisibility(View.GONE);
         String noDevices = getResources().getText(R.string.none_paired)
               .toString();
         mPairedDevicesArrayAdapter.add(noDevices);
      }
   }

   @Override
   protected void onStart() {
      super.onStart();
      doDiscovery();
   }

   @Override
   protected void onDestroy()
   {
      super.onDestroy();

      // 确保我们不再进行发现
      if (mBtAdapter != null)
      {
         mBtAdapter.cancelDiscovery();
      }

      //取消注册广播侦听器
      this.unregisterReceiver(mReceiver);
   }

   /**
    * 使用BluetoothAdapter启动设备发现
    */
   private void doDiscovery()
   {
      if (D) Log.d(TAG, "doDiscovery()");

      // 在标题中指示扫描
      setProgressBarIndeterminateVisibility(true);
      setTitle(R.string.scanning);

      // 开启新装置的副标题
      findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);

      // 如果我们已经发现,停止它
      if (mBtAdapter.isDiscovering())
      {
         mBtAdapter.cancelDiscovery();
      }
      //BluetoothAdapter请求发现
      mBtAdapter.startDiscovery();
   }

   // ListView中其他设备的点击监听器
   private OnItemClickListener mDeviceClickListener = new OnItemClickListener()
   {
      public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3)
      {
         //取消发现,我们m_about来连接
         mBtAdapter.cancelDiscovery();

         // 获取设备的MAC地址,这是视图中最后17个字符
         String info = ((TextView) v).getText().toString();
         String address = info.substring(info.length() - 17);

         // 创建结果意图并包括MAC地址
         Intent intent = new Intent();
         intent.putExtra(EXTRA_DEVICE_ADDRESS, address);
         intent.putExtra(EXTRA_LEGAL,false);
         // 设置结果并完成此活动
         setResult(Activity.RESULT_OK, intent);
         finish();
      }
   };
     //ListView中专用测试设备的点击监听器
   private  OnItemClickListener mZYDeviceClickListener = new OnItemClickListener() {
       @Override
       public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
          //取消发现,我们m_about来连接
          mBtAdapter.cancelDiscovery();

          // 获取设备的MAC地址,这是视图中最后17个字符
          String info = ((TextView) view).getText().toString();
          String address = info.substring(info.length() - 17);

          // 创建结果意图并包括MAC地址
          Intent intent = new Intent();
          intent.putExtra(EXTRA_DEVICE_ADDRESS, address);
          intent.putExtra(EXTRA_LEGAL,true);
          // 设置结果并完成此活动
          setResult(Activity.RESULT_OK, intent);
          finish();
       }
    };
   // BroadcastReceiver,侦听发现的设备,并在发现完成时更改标题
   private final BroadcastReceiver mReceiver = new BroadcastReceiver()
   {
      @Override
      public void onReceive(Context context, Intent intent)
      {
         String action = intent.getAction();
         //Intent获取BluetoothDevice对象
         BluetoothDevice device = intent
               .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
         // 发现找到设备时
         if (BluetoothDevice.ACTION_FOUND.equals(action))
         {    String devicename =device.getName();
            while (devicename==null){
               devicename =device.getName();
            }


            // 该设备没有配对,加载到新的通用蓝牙设备的列表

            if (device.getBondState() != BluetoothDevice.BOND_BONDED)
            {
               mNewDevicesArrayAdapter.add(device.getName() + "\n"
                     + device.getAddress());

            }
              //    再次得到的action,会等于PAIRING_REQUEST,进行配对操作
         }else if(BluetoothDevice.ACTION_PAIRING_REQUEST.equals(action)){
            String devicename =device.getName();
            while (devicename==null){
               devicename =device.getName();
            }
            Log.e(TAG,"接收到配对广播");


         }
         // 发现完成后,更改活动标题
         else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action))
         {
         setProgressBarIndeterminateVisibility(false);
         setTitle(R.string.select_device);

         if (mNewDevicesArrayAdapter.getCount() == 0)
         {
            String noDevices = getResources().getText(
               R.string.none_found).toString();
            mNewDevicesArrayAdapter.add(noDevices);
         }


      }
      }
   };

数据转换工具类  主要设置十六进制数据为ascll数据的转化

// 将字节数组转化为16进制字符串,确定长度
public static String bytesToHexString(byte[] bytes, int a) {
    String result = "";
    for (int i = 0; i < a; i++) {
        String hexString = Integer.toHexString(bytes[i] & 0xFF);// 将高24位置0
        if (hexString.length() == 1) {
            hexString = '0' + hexString;
        }
        result += hexString.toUpperCase();
    }
    return result;
}
// 将字节数组转化为16进制字符串,不确定长度
public static String Bytes2HexString(byte[] b) {
    String ret = "";
    for (int i =0; i < b.length; i++) {
        String hex = Integer.toHexString(b[i] & 0xFF);// 将高24位置0
        if (hex.length() == 1) {
            hex = '0' + hex;
        }
        ret += hex.toUpperCase();
    }
    return ret;
}
// 16进制字符串转化为字节数组
public static byte[] hexStr2Bytes(String paramString) {
    int i = paramString.length() / 2;

    byte[] arrayOfByte = new byte[i];
    int j = 0;
    while (true) {
        if (j >= i)
            return arrayOfByte;
        int k = 1 + j * 2;
        int l = k + 1;
        arrayOfByte[j] = (byte) (0xFF & Integer.decode(
                "0x" + paramString.substring(j * 2, k)
                        + paramString.substring(k, l)).intValue());
        ++j;
    }
}

最后附上运行的app界面截图

                                                                       


总结:

   这个项目总的来说是比较简单的,蓝牙通信谷歌都有相对应的蓝牙API封装。代码上去弄得比较繁琐,学习做的东西,还请各位请见谅,有什么意见和想法,欢迎留言,一起共同努力。

源码载址:https://download.csdn.net/download/sinat_27064327/10450642




猜你喜欢

转载自blog.csdn.net/sinat_27064327/article/details/80527460