转载请注明出处,谢谢http://blog.csdn.net/metalseed/article/details/7988945 by---MetalSeed
Android蓝牙操作:与蓝牙串口模块通信,或其他蓝牙设备通信。
初涉android的蓝牙操作,按照固定MAC地址连接获取Device时,程序始终是异常终止,查了好多天代码都没查出原因。今天改了一下API版本,突然就成功连接了。总结之后发现果然是个坑爹之极的错误。
为了这种错误拼命查原因浪费大把时间是非常不值得的,但是问题不解决更是揪心。可惜我百度了那么多,都没有给出确切原因。今天特此mark,希望后来者遇到这个问题的时候能轻松解决。
下面是我的连接过程,中间崩溃原因及解决办法。
1:用AT指令获得蓝牙串口的MAC地址,地址是简写的,按照常理猜测可得标准格式。
2:开一个String adress= "************" //MAC地址, String MY_UUID= "************"//UUID根据通信而定,网上都有。
3:取得本地Adapter用getDefaultAdapter(); 远程的则用getRemoteDevice(adress); 之后便可用UUID开socket进行通信。
如果中途各种在getRemoteDevice处崩溃,大家可以查看一下当前的API版本,如果是2.1或以下版本的话,便能确定是API版本问题,只要换成2.2或者以上就都可以正常运行了~ 这么坑爹的错误的确很为难初学者。 唉·········· 为这种小trick浪费很多时间真是难过。
(另外有个重要地方,别忘了给manifest里面加以下两个蓝牙操作权限哦~)
- <uses-permission android:name="android.permission.BLUETOOTH"></uses-permission>
- <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"></uses-permission>
下面附上Android蓝牙操作中用固定MAC地址传输信息的模板,通用搜索模式日后再补删模板:
- private BluetoothAdapter mBluetoothAdapter = null;
- private BluetoothSocket btSocket = null;
- private OutputStream outStream = null;
- private InputStream inStream = null;
- private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //这条是蓝牙串口通用的UUID,不要更改
- private static String address = "00:12:02:22:06:61"; // <==要连接的蓝牙设备MAC地址
- /*获得通信线路过程*/
- /*1:获取本地BlueToothAdapter*/
- mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
- if(mBluetoothAdapter == null)
- {
- Toast.makeText(this, "Bluetooth is not available.", Toast.LENGTH_LONG).show();
- finish();
- return;
- }
- if(!mBluetoothAdapter.isEnabled())
- {
- Toast.makeText(this, "Please enable your Bluetooth and re-run this program.", Toast.LENGTH_LONG).show();
- finish();
- return;
- }
- /*2:获取远程BlueToothDevice*/
- BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
- if(mBluetoothAdapter == null)
- {
- Toast.makeText(this, "Can't get remote device.", Toast.LENGTH_LONG).show();
- finish();
- return;
- }
- /*3:获得Socket*/
- try {
- btSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
- } catch (IOException e) {
- Log.e(TAG, "ON RESUME: Socket creation failed.", e);
- }
- /*4:取消discovered节省资源*/
- mBluetoothAdapter.cancelDiscovery();
- /*5:连接*/
- try {
- btSocket.connect();
- Log.e(TAG, "ON RESUME: BT connection established, data transfer link open.");
- } catch (IOException e) {
- try {
- btSocket.close();
- } catch (IOException e2) {
- Log .e(TAG,"ON RESUME: Unable to close socket during connection failure", e2);
- }
- }
- /*此时可以通信了,放在任意函数中*/
- /* try {
- outStream = btSocket.getOutputStream();
- inStream = btSocket.getInputStream(); //可在TextView里显示
- } catch (IOException e) {
- Log.e(TAG, "ON RESUME: Output stream creation failed.", e);
- }
- String message = "1";
- byte[] msgBuffer = message.getBytes();
- try {
- outStream.write(msgBuffer);
- } catch (IOException e) {
- Log.e(TAG, "ON RESUME: Exception during write.", e);
- }
- */
通用搜索模式代码模板:
简洁简洁方式1 demo
作用: 用VerticalSeekBar控制一个 LED屏幕的亮暗。
直接上码咯~
- package com.example.seed2;
- import android.app.Activity;
- import android.app.AlertDialog;
- import android.app.Dialog;
- import android.os.Bundle;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.util.UUID;
- import android.bluetooth.BluetoothAdapter;
- import android.bluetooth.BluetoothDevice;
- import android.bluetooth.BluetoothSocket;
- import android.content.DialogInterface;
- import android.util.Log;
- import android.view.KeyEvent;
- import android.widget.Toast;
- public class MetalSeed extends Activity {
- private static final String TAG = "BluetoothTest";
- private BluetoothAdapter mBluetoothAdapter = null;
- private BluetoothSocket btSocket = null;
- private OutputStream outStream = null;
- private InputStream inStream = null;
- private VerticalSeekBar vskb = null;
- private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //这条是蓝牙串口通用的UUID,不要更改
- private static String address = "00:12:02:22:06:61"; // <==要连接的蓝牙设备MAC地址
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- this.vskb = (VerticalSeekBar)super.findViewById(R.id.mskb);
- this.vskb.setOnSeekBarChangeListener(new OnSeekBarChangeListenerX());
- mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
- if(mBluetoothAdapter == null)
- {
- Toast.makeText(this, "Bluetooth is not available.", Toast.LENGTH_LONG).show();
- finish();
- return;
- }
- if(!mBluetoothAdapter.isEnabled())
- {
- Toast.makeText(this, "Please enable your Bluetooth and re-run this program.", Toast.LENGTH_LONG).show();
- finish();
- return;
- }
- }
- private class OnSeekBarChangeListenerX implements VerticalSeekBar.OnSeekBarChangeListener {
- public void onProgressChanged(VerticalSeekBar seekBar, int progress, boolean fromUser) {
- //Main.this.clue.setText(seekBar.getProgress());
- /* String message;
- byte [] msgBuffer;
- try {
- outStream = btSocket.getOutputStream();
- } catch (IOException e) {
- Log.e(TAG,"ON RESUME : Output Stream creation failed.", e);
- }
- message =Integer.toString( seekBar.getProgress() );
- msgBuffer = message.getBytes();
- try{
- outStream.write(msgBuffer);
- } catch (IOException e) {
- Log.e (TAG, "ON RESUME : Exception during write.", e);
- } */
- }
- public void onStartTrackingTouch(VerticalSeekBar seekBar) {
- String message;
- byte [] msgBuffer;
- try {
- outStream = btSocket.getOutputStream();
- } catch (IOException e) {
- Log.e(TAG,"ON RESUME : Output Stream creation failed.", e);
- }
- message =Integer.toString( seekBar.getProgress() );
- msgBuffer = message.getBytes();
- try{
- outStream.write(msgBuffer);
- } catch (IOException e) {
- Log.e (TAG, "ON RESUME : Exception during write.", e);
- }
- }
- public void onStopTrackingTouch(VerticalSeekBar seekBar) {
- String message;
- byte [] msgBuffer;
- try {
- outStream = btSocket.getOutputStream();
- } catch (IOException e) {
- Log.e(TAG,"ON RESUME : Output Stream creation failed.", e);
- }
- message =Integer.toString( seekBar.getProgress() );
- msgBuffer = message.getBytes();
- try{
- outStream.write(msgBuffer);
- } catch (IOException e) {
- Log.e (TAG, "ON RESUME : Exception during write.", e);
- }
- }
- }
- @Override
- public void onStart()
- {
- super.onStart();
- }
- @Override
- public void onResume()
- {
- super.onResume();
- BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
- try {
- btSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
- } catch (IOException e) {
- Log.e(TAG, "ON RESUME: Socket creation failed.", e);
- }
- mBluetoothAdapter.cancelDiscovery();
- try {
- btSocket.connect();
- Log.e(TAG, "ON RESUME: BT connection established, data transfer link open.");
- } catch (IOException e) {
- try {
- btSocket.close();
- } catch (IOException e2) {
- Log .e(TAG,"ON RESUME: Unable to close socket during connection failure", e2);
- }
- }
- // Create a data stream so we can talk to server.
- /* try {
- outStream = btSocket.getOutputStream();
- inStream = btSocket.getInputStream();
- } catch (IOException e) {
- Log.e(TAG, "ON RESUME: Output stream creation failed.", e);
- }
- String message = "read";
- byte[] msgBuffer = message.getBytes();
- try {
- outStream.write(msgBuffer);
- } catch (IOException e) {
- Log.e(TAG, "ON RESUME: Exception during write.", e);
- }
- int ret = -1;
- while( ret != -1)
- {
- try {
- ret = inStream.read();
- } catch (IOException e)
- {
- e.printStackTrace();
- }
- }
- */
- }
- @Override
- public void onPause()
- {
- super.onPause();
- if (outStream != null)
- {
- try {
- outStream.flush();
- } catch (IOException e) {
- Log.e(TAG, "ON PAUSE: Couldn't flush output stream.", e);
- }
- }
- try {
- btSocket.close();
- } catch (IOException e2) {
- Log.e(TAG, "ON PAUSE: Unable to close socket.", e2);
- }
- }
- @Override
- public void onStop()
- {
- super.onStop();
- }
- @Override
- public void onDestroy()
- {
- super.onDestroy();
- }
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event){
- if(keyCode == KeyEvent.KEYCODE_BACK){
- this.exitDialog();
- }
- return false;
- }
- private void exitDialog(){
- Dialog dialog = new AlertDialog.Builder(MetalSeed.this)
- .setTitle("退出程序?")
- .setMessage("您确定要退出本程序吗?")
- .setPositiveButton("确定", new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int whichButton) {
- MetalSeed.this.finish();
- }
- }).setNegativeButton("取消", new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int whichButton) { }
- }).create();
- dialog.show();
- }
- }
此为上述demo的layout
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@drawable/bcf" >
- <TextView
- android:id="@+id/myt"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:layout_centerHorizontal="true"
- android:layout_marginTop="48dp"
- android:text="MetalSeed"
- android:textSize="40dip" />
- <com.example.seed2.VerticalSeekBar
- android:id="@+id/mskb"
- android:layout_width="105dp"
- android:layout_height="219dp"
- android:layout_below="@+id/myt"
- android:layout_centerHorizontal="true"
- android:layout_marginTop="85dp"
- android:maxHeight="95dip"
- android:minHeight="95dip"
- android:minWidth="95dip"
- android:thumbOffset="0dip" />
- </RelativeLayout>