我想创建两个应用程序,一个用于通过蓝牙发送文本,另一个用于接收它。但问题是,即使两个设备连接成功,也没有文本传输。特别是Messages活动中的 outStream.write(bytes) 无效。
与大多数问题不同,我只想要从Sender到Receiver的单向单面聊天;不是双向聊天。
任何帮助都将不胜感激。
这是发件人代码:
//member variables
private BluetoothAdapter btAdapter=null;
private ConnectThread btConnectThread;
private ConnectedThread btConnectedThread;
private int btState;
// Constants that indicate the current connection state
public static final int STATE_NONE = 0; // we're doing nothing
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
//dev name to be returned to UI
private static final int DEVICE_NAME=0;
//sent message returned to UI
private static final int SENT_MESSAGE=1;
private static final int STATUS=2;
/**
* Return Intent extra
*/
public static String EXTRA_DEVICE_ADDRESS = "device_address";
// Unique UUID for this application
private static final UUID MY_UUID = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");
//handler for UI thread
private final Handler handle=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
TextView dvNm=(TextView) findViewById(R.id.connectedTo);
TextView sntMsg=(TextView) findViewById(R.id.sentMessage);
TextView stat=(TextView) findViewById(R.id.statusTest);
EditText tyMsg=(EditText) findViewById(R.id.typedMessage);
String temp;
switch (msg.what)
{
case DEVICE_NAME:
{
temp=dvNm.getText().toString();
dvNm.setText(temp+": "+msg.obj.toString());
break;
}
case SENT_MESSAGE:
{
temp=msg.obj.toString();
sntMsg.setText("Sent: "+temp);
tyMsg.setText("");
break;
}
case STATUS:
{
temp=msg.obj.toString();
stat.setText(temp);
}
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messages);
btAdapter=BluetoothAdapter.getDefaultAdapter();
}
@Override
protected void onStart() {
super.onStart();
Intent dList=getIntent();
String macAddr=dList.getStringExtra(EXTRA_DEVICE_ADDRESS);
if(btState==STATE_NONE)
{
connect(macAddr);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if(btState!=STATE_NONE)
stop();
}
//button listener for sending message
public void onSend(View v)
{
//get the typed message
EditText tyMsg=(EditText) findViewById(R.id.typedMessage);
//convert it to byte format
byte[] send=tyMsg.getText().toString().getBytes();
// Create temporary object
ConnectedThread cThrd;
// Synchronize a copy of the ConnectedThread
synchronized (this) {
if (btState != STATE_CONNECTED) return;
cThrd = btConnectedThread;
}
// Perform the write asynchronized
cThrd.write(send);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_messages, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* Bluetooth Client component code
*/
private class ConnectThread extends Thread {
private final BluetoothSocket btSocket;
private final BluetoothDevice btDevice;
public ConnectThread(BluetoothDevice device) {
// Use a temporary object that is later assigned to btSocket,
// because btSocket is final
BluetoothSocket tmp = null;
btDevice = device;
// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
// MY_UUID is the app's UUID string, also used by the server code
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) { }
btSocket = tmp;
}
public void run() {
// Cancel discovery because it will slow down the connection
btAdapter.cancelDiscovery();
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
btSocket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and get out
try {
btSocket.close();
} catch (IOException closeException) { }
return;
}
// Do work to manage the connection (in a separate thread)
connected(btSocket,btDevice);
}
/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
btSocket.close();
} catch (IOException e) { }
}
}
/**
* Code to manage the connected socket
*/
private class ConnectedThread extends Thread {
private final BluetoothSocket btSocket;
private final OutputStream outStream;
public ConnectedThread(BluetoothSocket socket) {
btSocket = socket;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
outStream = tmpOut;
}
public void run() { }
/* Call this from the main activity to send data to the remote device */
public void write(byte[] bytes) {
try {
Message msg2=handle.obtainMessage(STATUS,"Inside write of connectedthread");
handle.sendMessage(msg2);
outStream.write(bytes);
outStream.flush();
Message msg1=handle.obtainMessage(STATUS,"Wrote to outstream");
handle.sendMessage(msg1);
Message msg=handle.obtainMessage(SENT_MESSAGE,bytes);
handle.sendMessage(msg);
} catch (IOException e) { }
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
btSocket.close();
} catch (IOException e) { }
}
}
/**
* Start the ConnectThread to initiate a connection to a remote device.
*
* @param macAddr is the mac-address The BluetoothDevice to connect
*/
public synchronized void connect(String macAddr) {
//get Bluetooth device from mac-address
BluetoothDevice device = btAdapter.getRemoteDevice(macAddr);
// Cancel any thread attempting to make a connection
if (btState == STATE_CONNECTING) {
if (btConnectThread != null) {
btConnectThread.cancel();
btConnectThread = null;
}
}
// Cancel any thread currently running a connection
if (btConnectedThread != null) {
btConnectedThread.cancel();
btConnectedThread = null;
}
// Start the thread to connect with the given device
btConnectThread = new ConnectThread(device);
btConnectThread.start();
btState=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) {
// Cancel the thread that completed the connection
if (btConnectThread != null) {
btConnectThread.cancel();
btConnectThread = null;
}
// Cancel any thread currently running a connection
if (btConnectedThread != null) {
btConnectedThread.cancel();
btConnectedThread = null;
}
// Start the thread to manage the connection and perform transmissions
btConnectedThread = new ConnectedThread(socket);
btConnectedThread.start();
// Send the name of the connected device back to the UI Activity
Message msg = handle.obtainMessage(DEVICE_NAME,device.getName());
handle.sendMessage(msg);
btState=STATE_CONNECTED;
}
/**
* Stop all threads
*/
public synchronized void stop(){
// Cancel the thread that completed the connection
if (btConnectThread != null) {
btConnectThread.cancel();
btConnectThread = null;
}
// Cancel any thread currently running a connection
if (btConnectedThread != null) {
btConnectedThread.cancel();
btConnectedThread = null;
}
btState=STATE_NONE;
}
}
这是收件人代码:
//member variables
private BluetoothAdapter btAdapter=null;
private AcceptThread btAcceptThread;
private ConnectedThread btConnectedThread;
private int btState;
// 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_CONNECTED = 3; // now connected to a remote device
//dev name to be returned to UI
private static final int DEVICE_NAME=0;
//received message returned to UI
private static final int RECEIVED_MESSAGE=1;
// Name for the SDP record when creating server socket
private static final String NAME = "BluetoothAnnouncement";
// Unique UUID for this application
private static final UUID MY_UUID = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");
//handler for UI thread
private final Handler handle=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
TextView dvNm=(TextView) findViewById(R.id.connectedTo);
TextView rcvdMsg=(TextView) findViewById(R.id.receivedMessage);
String temp;
switch (msg.what)
{
case DEVICE_NAME:
{
temp=dvNm.getText().toString();
dvNm.setText(temp+": "+msg.obj.toString());
break;
}
case RECEIVED_MESSAGE:
{
temp=msg.obj.toString();
rcvdMsg.setText("Received: "+temp);
break;
}
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Acquiring Bluetooth Adapter
btAdapter = BluetoothAdapter.getDefaultAdapter();
//setting initial state
}
@Override
protected void onStart() {
super.onStart();
if(!btAdapter.isEnabled())
{
Toast.makeText(this, "Please enable Bluetooth to receive announcements",
Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onResume() {
super.onResume();
if(btAdapter.isEnabled())
{
if(btState==STATE_NONE)
{
start();
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if(btState!=STATE_NONE)
stop();
}
//enabling Bluetooth
public void btEnable(View v)
{
if (btAdapter.isEnabled())
{
Toast.makeText(this, "Bluetooth already enabled",
Toast.LENGTH_SHORT).show();
}
else
{
Intent discoverableIntent = new
Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 0);
startActivity(discoverableIntent);
}
}
/**
* Server component code
*/
private class AcceptThread extends Thread {
private final BluetoothServerSocket btServerSocket;
public AcceptThread() {
// Use a temporary object that is later assigned to btServerSocket,
// because btServerSocket is final
BluetoothServerSocket tmp = null;
try {
// MY_UUID is the app's UUID string, also used by the client code
tmp = btAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (IOException e) { }
btServerSocket = tmp;
}
public void run() {
BluetoothSocket socket = null;
BluetoothDevice device;
// Keep listening until exception occurs or a socket is returned
while (true) {
try {
socket = btServerSocket.accept();
} catch (IOException e) {
break;
}
// If a connection was accepted
if (socket != null) {
device=socket.getRemoteDevice();
// Do work to manage the connection (in a separate thread)
connected(socket, device);
try {
btServerSocket.close();
} catch (IOException e) { }
break;
}
}
}
/** Will cancel the listening socket, and cause the thread to finish */
public void cancel() {
try {
btServerSocket.close();
} catch (IOException e) { }
}
}
/**
* Code to manage the connected socket
*/
private class ConnectedThread extends Thread {
private final BluetoothSocket btSocket;
private final InputStream inStream;
public ConnectedThread(BluetoothSocket socket) {
btSocket = socket;
InputStream tmpIn = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
} catch (IOException e) { }
inStream = tmpIn;
}
public void run() {
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = inStream.read(buffer);
// Send the obtained bytes to the UI activity
Message msg = handle.obtainMessage(RECEIVED_MESSAGE,bytes);
handle.sendMessage(msg);
} catch (IOException e) {
break;
}
}
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
btSocket.close();
} catch (IOException e) { }
}
}
/**
* Start the chat service. Specifically start AcceptThread to begin a
* session in listening (server) mode. Called by the Activity onResume()
*/
public synchronized void start() {
// Cancel any thread currently running a connection
if (btConnectedThread != null) {
btConnectedThread.cancel();
btConnectedThread = null;
}
// Start the thread to listen on a BluetoothServerSocket
if (btAcceptThread == null) {
btAcceptThread = new AcceptThread();
btAcceptThread.start();
}
//set state
btState=STATE_LISTEN;
}
/**
* 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) {
// Cancel any thread currently running a connection
if (btConnectedThread != null) {
btConnectedThread.cancel();
btConnectedThread = null;
}
// Cancel the accept thread because we only want to connect to one device
if (btAcceptThread != null) {
btAcceptThread.cancel();
btAcceptThread = null;
}
// Start the thread to manage the connection and perform transmissions
btConnectedThread = new ConnectedThread(socket);
btConnectedThread.start();
// Send the name of the connected device back to the UI Activity
Message msg = handle.obtainMessage(DEVICE_NAME,device.getName());
handle.sendMessage(msg);
btState=STATE_CONNECTED;
}
/**
* Stop all threads
*/
public synchronized void stop(){
// Cancel any thread currently running a connection
if (btConnectedThread != null) {
btConnectedThread.cancel();
btConnectedThread = null;
}
// Cancel the accept thread because we only want to connect to one device
if (btAcceptThread != null) {
btAcceptThread.cancel();
btAcceptThread = null;
}
btState=STATE_NONE;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}