问题
I am going to implemenet the module for sending commands from my Android smartphone to HC-06 via BLuetooth. WHen it comes to the execution , it show s the following exception and find no clue for the error message as title . Would you please tell the way to modifiy ?
Exception Log Message :
07-29 13:51:37.701: W/BluetoothAdapter(1928): getBluetoothService() called with no BluetoothManagerCallback
07-29 13:51:37.711: D/BluetoothSocket(1928): connect(), SocketState: INIT, mPfd: {ParcelFileDescriptor: FileDescriptor[51]}
07-29 13:51:42.831: W/System.err(1928): java.io.IOException: read failed, socket might closed or timeout, read ret: -1
07-29 13:51:42.831: W/System.err(1928): at android.bluetooth.BluetoothSocket.readAll(BluetoothSocket.java:505)
07-29 13:51:42.831: W/System.err(1928): at android.bluetooth.BluetoothSocket.readInt(BluetoothSocket.java:516)
07-29 13:51:42.831: W/System.err(1928): at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:320)
07-29 13:51:42.831: W/System.err(1928): at com.luugiathuy.apps.remotebluetooth.BluetoothCommandService$ConnectThread.run(BluetoothCommandService.java:260)
07-29 13:51:42.831: D/BluetoothCommandService(1928): setState() 2 -> 1
The below is my code
public class BluetoothCommandService {
// Debugging
private static final String TAG = "BluetoothCommandService";
private static final boolean D = true;
// Unique UUID for this application
// private static final UUID MY_UUID = UUID.fromString("04c6093b-0000-1000-8000-00805f9b34fb");
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
// Member fields
private final BluetoothAdapter mAdapter;
private final Handler mHandler;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private int mState;
// private BluetoothDevice mSavedDevice;
// private int mConnectionLostCount;
// Constants that indicate the current connection state
public static final int STATE_NONE = 0; // we're doing nothing
public static final int STATE_LISTEN = 1; // now listening for incoming connections
public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
public static final int STATE_CONNECTED = 3; // now connected to a remote device
// Constants that indicate command to computer
public static final int EXIT_CMD = -1;
public static final int VOL_UP = 1;
public static final int VOL_DOWN = 2;
public static final int MOUSE_MOVE = 3;
/**
* Constructor. Prepares a new BluetoothChat session.
* @param context The UI Activity Context
* @param handler A Handler to send messages back to the UI Activity
*/
public BluetoothCommandService(Context context, Handler handler) {
mAdapter = BluetoothAdapter.getDefaultAdapter();
mState = STATE_NONE;
//mConnectionLostCount = 0;
mHandler = handler;
}
/**
* Set the current state of the chat connection
* @param state An integer defining the current connection 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(RemoteBluetooth.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
}
/**
* Return the current connection state. */
public synchronized int getState() {
return mState;
}
/**
* Start the chat service. Specifically start AcceptThread to begin a
* session in listening (server) mode. Called by the Activity onResume() */
public synchronized void start() {
if (D) Log.d(TAG, "start");
// Cancel any thread attempting to make a connection
if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
setState(STATE_LISTEN);
}
/**
* Start the ConnectThread to initiate a connection to a remote device.
* @param device The BluetoothDevice to connect
*/
public synchronized void connect(BluetoothDevice device) {
if (D) Log.d(TAG, "connect to: " + device);
// Cancel any thread attempting to make a connection
if (mState == STATE_CONNECTING) {
if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
// Start the thread to connect with the given device
mConnectThread = new ConnectThread(device);
mConnectThread.start();
setState(STATE_CONNECTING);
}
/**
* Start the ConnectedThread to begin managing a Bluetooth connection
* @param socket The BluetoothSocket on which the connection was made
* @param device The BluetoothDevice that has been connected
*/
public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
if (D) Log.d(TAG, "connected");
// Cancel the thread that completed the connection
if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
// Start the thread to manage the connection and perform transmissions
mConnectedThread = new ConnectedThread(socket);
mConnectedThread.start();
// Send the name of the connected device back to the UI Activity
Message msg = mHandler.obtainMessage(RemoteBluetooth.MESSAGE_DEVICE_NAME);
Bundle bundle = new Bundle();
bundle.putString(RemoteBluetooth.DEVICE_NAME, device.getName());
msg.setData(bundle);
mHandler.sendMessage(msg);
// save connected device
//mSavedDevice = device;
// reset connection lost count
//mConnectionLostCount = 0;
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;}
setState(STATE_NONE);
}
/**
* Write to the ConnectedThread in an unsynchronized manner
* @param out The bytes to write
* @see ConnectedThread#write(byte[])
*/
public void write(byte[] out) {
// Create temporary object
ConnectedThread r;
// Synchronize a copy of the ConnectedThread
synchronized (this) {
if (mState != STATE_CONNECTED) return;
r = mConnectedThread;
}
// Perform the write unsynchronized
r.write(out);
}
public void write(int out) {
// Create temporary object
ConnectedThread r;
// Synchronize a copy of the ConnectedThread
synchronized (this) {
if (mState != STATE_CONNECTED) return;
r = mConnectedThread;
}
// Perform the write unsynchronized
r.write(out);
}
/**
* Indicate that the connection attempt failed and notify the UI Activity.
*/
private void connectionFailed() {
setState(STATE_LISTEN);
// Send a failure message back to the Activity
Message msg = mHandler.obtainMessage(RemoteBluetooth.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(RemoteBluetooth.TOAST, "Unable to connect device");
msg.setData(bundle);
mHandler.sendMessage(msg);
}
/**
* Indicate that the connection was lost and notify the UI Activity.
*/
private void connectionLost() {
// mConnectionLostCount++;
// if (mConnectionLostCount < 3) {
// // Send a reconnect message back to the Activity
// Message msg = mHandler.obtainMessage(RemoteBluetooth.MESSAGE_TOAST);
// Bundle bundle = new Bundle();
// bundle.putString(RemoteBluetooth.TOAST, "Device connection was lost. Reconnecting...");
// msg.setData(bundle);
// mHandler.sendMessage(msg);
//
// connect(mSavedDevice);
// } else {
setState(STATE_LISTEN);
// Send a failure message back to the Activity
Message msg = mHandler.obtainMessage(RemoteBluetooth.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(RemoteBluetooth.TOAST, "Device connection was lost");
msg.setData(bundle);
mHandler.sendMessage(msg);
// }
}
/**
* This thread runs while attempting to make an outgoing connection
* with a device. It runs straight through; the connection either
* succeeds or fails.
*/
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
mmDevice = device;
BluetoothSocket tmp = null;
// Get a BluetoothSocket for a connection with the
// given BluetoothDevice
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");
// Always cancel discovery because it will slow down a connection
mAdapter.cancelDiscovery();
// Make a connection to the BluetoothSocket
try {
// This is a blocking call and will only return on a
// successful connection or an exception
mmSocket.connect();
} catch (IOException e) {
e.printStackTrace();
connectionFailed();
// Close the socket
try {
mmSocket.close();
} catch (IOException e2) {
Log.e(TAG, "unable to close() socket during connection failure", e2);
}
// Start the service over to restart listening mode
BluetoothCommandService.this.start();
return;
}
// Reset the ConnectThread because we're done
synchronized (BluetoothCommandService.this) {
mConnectThread = null;
}
// Start the connected thread
connected(mmSocket, mmDevice);
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
/**
* This thread runs during a connection with a remote device.
* It handles all incoming and outgoing transmissions.
*/
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;
// Get the BluetoothSocket input and output streams
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];
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
int bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(RemoteBluetooth.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
break;
}
}
}
/**
* Write to the connected OutStream.
* @param buffer The bytes to write
*/
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
mmOutStream.flush();
// Share the sent message back to the UI Activity
// mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer)
// .sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
public void write(int out) {
try {
mmOutStream.write(out);
// Share the sent message back to the UI Activity
// mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer)
// .sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
public void cancel() {
try {
mmOutStream.write(EXIT_CMD);
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
}
Here is my Activity
public class RemoteBluetooth extends Activity {
// Layout view
private TextView mTitle;
// Intent request codes
private static final int REQUEST_CONNECT_DEVICE = 1;
private static final int REQUEST_ENABLE_BT = 2;
// Message types sent from the 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;
// Key names received from the BluetoothCommandService Handler
public static final String DEVICE_NAME = "device_name";
public static final String TOAST = "toast";
// Name of the connected device
private String mConnectedDeviceName = null;
// Local Bluetooth adapter
private BluetoothAdapter mBluetoothAdapter = null;
// Member object for Bluetooth Command Service
private BluetoothCommandService mCommandService = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set up the window layout
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
setContentView(R.layout.main);
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title);
// Set up the custom title
mTitle = (TextView) findViewById(R.id.title_left_text);
mTitle.setText(R.string.app_name);
mTitle = (TextView) findViewById(R.id.title_right_text);
// Get local Bluetooth adapter
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// If the adapter is null, then Bluetooth is not supported
if (mBluetoothAdapter == null) {
Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show();
finish();
return;
}
}
@Override
protected void onStart() {
super.onStart();
// If BT is not on, request that it be enabled.
// setupCommand() will then be called during onActivityResult
if (!mBluetoothAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
// otherwise set up the command service
else {
if (mCommandService==null)
setupCommand();
}
}
@Override
protected void onResume() {
super.onResume();
// Performing this check in onResume() covers the case in which BT was
// not enabled during onStart(), so we were paused to enable it...
// onResume() will be called when ACTION_REQUEST_ENABLE activity returns.
if (mCommandService != null) {
if (mCommandService.getState() == BluetoothCommandService.STATE_NONE) {
mCommandService.start();
}
}
}
private void setupCommand() {
// Initialize the BluetoothChatService to perform bluetooth connections
mCommandService = new BluetoothCommandService(this, mHandler);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mCommandService != null)
mCommandService.stop();
}
private void ensureDiscoverable() {
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);
}
}
// The Handler that gets information back from the BluetoothChatService
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_STATE_CHANGE:
switch (msg.arg1) {
case BluetoothCommandService.STATE_CONNECTED:
mTitle.setText(R.string.title_connected_to);
mTitle.append("HC-06");
break;
case BluetoothCommandService.STATE_CONNECTING:
mTitle.setText(R.string.title_connecting);
break;
case BluetoothCommandService.STATE_LISTEN:
case BluetoothCommandService.STATE_NONE:
mTitle.setText(R.string.title_not_connected);
break;
}
break;
case MESSAGE_DEVICE_NAME:
// save the connected device's name
mConnectedDeviceName = msg.getData().getString(DEVICE_NAME);
Toast.makeText(getApplicationContext(), "Connected to "
+ mConnectedDeviceName, Toast.LENGTH_SHORT).show();
break;
case MESSAGE_TOAST:
Toast.makeText(getApplicationContext(), msg.getData().getString(TOAST),
Toast.LENGTH_SHORT).show();
break;
}
}
};
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CONNECT_DEVICE:
// When DeviceListActivity returns with a device to connect
if (resultCode == Activity.RESULT_OK) {
// Get the device MAC address
String address = data.getExtras()
.getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
// Get the BLuetoothDevice object
BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address);
// Attempt to connect to the device
mCommandService.connect(device);
}
break;
case REQUEST_ENABLE_BT:
// When the request to enable Bluetooth returns
if (resultCode == Activity.RESULT_OK) {
// Bluetooth is now enabled, so set up a chat session
setupCommand();
} else {
// User did not enable Bluetooth or an error occured
Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();
finish();
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.option_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.scan:
// Launch the DeviceListActivity to see devices and do scan
Intent serverIntent = new Intent(this, DeviceListActivity.class);
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
return true;
case R.id.discoverable:
// Ensure this device is discoverable by others
ensureDiscoverable();
return true;
}
return false;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
String blinkCommand = "&$V00X77V0" ;
String empty = "";
for (int i = 0 ; i < (100 - blinkCommand.length()) ; i ++){
empty += "0";
}
String limiter = "\r\n";
String fullCommand = blinkCommand + empty + limiter;
mCommandService.write(fullCommand.getBytes());
// mCommandService.write(BluetoothCommandService.VOL_UP);
return true;
}
else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN){
String blinkCommand = "&$V00X77V0" + "\r\n";
mCommandService.write(blinkCommand.getBytes());
// mCommandService.write(BluetoothCommandService.VOL_DOWN);
return true;
}
return super.onKeyDown(keyCode, event);
}
}
回答1:
since android 4.2 , bluetooth stack changed, so i guess you are testing on android>=4.2 .
your problem is here tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
. this socket creation method is not compatible starting with 4.2 , so you will need to use the fallback one after it fails : tmp =(BluetoothSocket) device.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(device,1);
Don't worry about called with no BluetoothManagerCallback
being thrown, it doesn't matter.
So if you do it like this, it will work:
try {
socket = device.createRfcommSocketToServiceRecord(SERIAL_UUID);
} catch (Exception e) {Log.e("","Error creating socket");}
try {
socket.connect();
Log.e("","Connected");
} catch (IOException e) {
Log.e("",e.getMessage());
try {
Log.e("","trying fallback...");
socket =(BluetoothSocket) device.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(device,1);
socket.connect();
Log.e("","Connected");
}
also, i answered here more detailed, about a similar problem.
来源:https://stackoverflow.com/questions/25009052/getbluetoothservice-called-with-no-bluetoothmanagercallback-for-android-nexus