我正在开发一个蓝牙聊天应用程序,这是SDK附带的示例中的一个扩展版本。它看起来更像是WhatsApp。我有主要的Conversations活动(基本上是包含用户聊天的列表视图),以及实际的聊天活动(BluetoothChatActivity),文本输入和发送按钮的文本视图等。我有BluetoothChatService类,就像在示例中一样但问题是会话活动和聊天活动都应该使用它(ConversationsActivity用于连接,BluetoothChatActivity用于消息传递)。每个活动都有自己的处理程序,例如当我尝试使用BluetoothChatActivity类编写消息时,ConversationsActivity处理程序就是处理它的人。我所做的是为每个活动设置一个BluetoothChatService成员,在它的构造函数中,我传递了活动的处理程序,一次在ConversationsActivity中,一次在BluetoothChatActivity中。 我长期坚持这个问题而且我不知道该怎么办......如果有人能帮助我,我会很高兴。
谢谢:)
添加代码(它不是everthing,只是相关部分):
ConversationsActivity:
public class ConversationsActivity extends ListActivity implements OnItemClickListener {
private static final String TAG = "ConversationsActivity";
public static final String DIRECTORY_PATH = Environment.getExternalStorageDirectory()+"/ChatApp";
// Message types sent from the BluetoothChatService Handler
public static final int START_CONVERSATION = 7;
public final Handler messagesHandler = new Handler() {
@Override
public void handleMessage(Message receivedMessage) {
Log.d(TAG, "Inside Handle message of conversation activity");
Log.d(TAG, String.valueOf(receivedMessage.what));
Log.d(TAG, String.valueOf(chatService.getState()));
switch (receivedMessage.what) {
case START_CONVERSATION:
String address = receivedMessage.getData().getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
String deviceName = receivedMessage.getData().getString(DeviceListActivity.EXTRA_DEVICE_NAME);
Log.d(TAG, "address = " + address + " deviceName = " + deviceName);
if (conversations.getUserByAddress(address) == null) // If the device is not inside the conversation array list
{
// Then add it to the conversation list
conversations.addConversation(new User(deviceName, address));
refreshConversationsList();
}
Log.e("Inside Connect Device", "YAY");
// Get the device MAC address
Intent chatIntent = new Intent(getBaseContext(), BluetoothChatActivity.class);
chatIntent.putExtra(DeviceListActivity.EXTRA_DEVICE_ADDRESS, address);
chatIntent.putExtra(DeviceListActivity.EXTRA_DEVICE_NAME, deviceName);
startActivity(chatIntent);
break;
case BluetoothChatActivity.MESSAGE_BE_SERVER:
chatService.stop();
chatService.start();
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initializeComponenets();
}
// Initialize neeed data
private void initializeComponenets() {
// TODO Auto-generated method stu
chatService = new BluetoothChatService(this, messagesHandler);
}
@Override
protected void onResume() {
super.onResume();
Log.e(TAG, "onResume");
if (chatService != null) {
// Only if the state is STATE_NONE, do we know that we haven't
// started already. Of course we check that BT is enabled
System.out.println(chatService.getState());
if (chatService.getState() == BluetoothChatService.STATE_NONE && bluetoothAdapter.isEnabled()) {
// Start the Bluetooth chat services
Log.d(String.valueOf(chatService.getState()), "IN RESUME");
chatService.start();
}
}
if (conversations.size() != 0)
refreshConversationsList();
}
BluetoothChatActivity:
public class BluetoothChatActivity extends Activity implements OnClickListener
{
// The Handler that gets information back from the BluetoothChatService
public final Handler messagesHandler = new Handler() {
@Override
public void handleMessage(Message receivedMessage) {
Log.d(TAG, "Message has obtained: " + String.valueOf(receivedMessage.what));
switch (receivedMessage.what) {
case MESSAGE_STATE_CHANGE:
switch (receivedMessage.arg1) {
case BluetoothChatService.STATE_CONNECTED:
Log.d(TAG, "state changed - STATE_CONNECTED");
conversationMessagesArrayAdapter.clear();
break;
case BluetoothChatService.STATE_CONNECTING:
Log.d(TAG, "state changed - STATE_CONNECTING");
actionBar.setSubtitle(getString(R.string.conversation_title_connecting));
break;
case BluetoothChatService.STATE_LISTEN:
Log.d(TAG, "state changed - STATE_LISTEN");
case BluetoothChatService.STATE_NONE:
Log.d(TAG, "state changed - STATE_NONE");
actionBar.setSubtitle(getString(R.string.conversation_title_not_connected));
break;
}
break;
case MESSAGE_WRITE:
Log.d(TAG, "Inside MESSAGE_WRITE");
byte[] writeBuf = (byte[]) receivedMessage.obj;
// construct a string from the buffer
String writeMessage = new String(writeBuf);
conversationMessagesArrayAdapter.add("Me: " + writeMessage);
refreshConversationChat();
break;
case MESSAGE_READ:
Log.d(TAG, "MESSAGE_READ");
byte[] readBuf = (byte[]) receivedMessage.obj;
// construct a string from the valid bytes in the buffer
String readMessage = new String(readBuf, 0, receivedMessage.arg1);
Log.e(TAG, "message received = " + readMessage);
conversationMessagesArrayAdapter.add(connectedDeviceName + ": " + readMessage);
refreshConversationChat();
break;
case MESSAGE_DEVICE_NAME:
// save the connected device's name
connectedDeviceName = receivedMessage.getData().getString(DEVICE_NAME);
actionBar.setSubtitle(getString(R.string.conversation_title_connected_to) + " " + connectedDeviceName);
Toast.makeText(getApplicationContext(), "Connected to "
+ connectedDeviceName, Toast.LENGTH_SHORT).show();
break;
case MESSAGE_TOAST:
Toast.makeText(getApplicationContext(), receivedMessage.getData().getString(TOAST),
Toast.LENGTH_SHORT).show();
break;
case MESSAGE_CANCEL_CONNECTION:
cancelConnection();
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bluetooth_chat);
initializeComponents();
}
private void initializeComponents() {
chatService = new BluetoothChatService(this, messagesHandler);
connectDevice(getIntent());
}
BluetoothChatService:
public class BluetoothChatService {
private final BluetoothAdapter bluetoothAdapter;
private final Handler messagesHandler; // A handler to send messages back to the UI activity
private AcceptThread acceptThread;
private ConnectThread connectThread;
private ConnectedThread connectedThread;
private int currentState;
private boolean isServer = false;
public static final String DEVICE_NAME = "deviceName";
public static final String DEVICE_ADDRESS = "deviceAddress";
// For Debugging
private static final String TAG = "BluetoothChatService";
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
private static final String NAME = "BluetoothChat";
private static UUID APP_UUID = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66"); // Default UUID at the beggining
public BluetoothChatService(Context context, Handler handler)
{
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
messagesHandler = handler;
currentState = STATE_NONE;
}
// this method sets the current state of the chat connection
private synchronized void setState(int state)
{
Log.d(TAG, "setState");
currentState = state;
// Give the new state to the Handler so the UI Activity can update
String stateDebug = "";
if (currentState == STATE_LISTEN)
isServer = true;
else
isServer = false;
messagesHandler.obtainMessage(BluetoothChatActivity.MESSAGE_STATE_CHANGE, currentState, -1).sendToTarget();
}
// This method returns the current connection state
public synchronized int getState()
{
String stateDebug = "";
switch (currentState)
{
case 0:
stateDebug = "STATE_NONE";
break;
case 1:
stateDebug = "STATE_LISTEN";
break;
case 2:
stateDebug = "STATE_CONNECTING";
break;
case 3:
stateDebug = "STATE_CONNECTED";
break;
}
Log.d(TAG, stateDebug);
return currentState;
}
/*
* This method starts the chat service. It initiates the Accept Thread in order to listen
* for incoming requests
*/
public synchronized void start()
{
Log.d(TAG, "start");
// Cancel any thread attempting to make a connection
if (connectThread != null)
{
connectThread.cancel();
connectThread = null;
}
// Cancel any thread currently running a connection
if (connectThread != null)
{
connectThread.cancel();
connectThread = null;
}
setState(STATE_LISTEN);
if (acceptThread == null)
{
acceptThread = new AcceptThread();
acceptThread.start();
}
isServer = true;
}
/*
* This method starts the ConnectThread to make a connection to a remote device
* This method receives as paramter the bluetooth device to connect to
*/
public synchronized void connect(BluetoothDevice remoteDevice)
{
Log.d(TAG, "connect");
// Cancel any thread attempting to make a connection
if (currentState == STATE_CONNECTING)
{
if (connectThread != null)
{
connectThread.cancel();
connectThread = null;
}
}
// Cancel any thread currently running a connection
// TODO: make the connected thread
if (connectedThread != null) {
connectedThread.cancel();
connectedThread = null;
}
// Start the thread to connect to the given device
connectThread = new ConnectThread(remoteDevice);
connectThread.start();
isServer = false;
setState(STATE_CONNECTING);
}
public synchronized void connected (BluetoothSocket socket, BluetoothDevice remoteDevice,
final String socketType)
{
Log.d(TAG, "connected");
// Cancel the thread that completed the connection
if (connectThread != null) {
connectThread.cancel();
connectThread = null;
}
// Cancel any thread currently running a connection
if (connectedThread != null) {
connectedThread.cancel();
connectedThread = null;
}
// Cancel the accept thread because we only want to connect to one
// device
if (acceptThread != null) {
acceptThread.cancel();
acceptThread = null;
}
// Start the thread to manage the connection and perform transmissions
connectedThread = new ConnectedThread(socket, socketType);
connectedThread.start();
if (currentState != STATE_CONNECTED)
{
getState();
// Send the name of the connected device back to the UI Activity
if (!isServer)
{
Message msg = messagesHandler.obtainMessage(BluetoothChatActivity.MESSAGE_DEVICE_NAME);
Bundle bundle = new Bundle();
bundle.putString(BluetoothChatActivity.DEVICE_NAME, remoteDevice.getName());
msg.setData(bundle);
messagesHandler.sendMessage(msg);
}
else
{
Message msg = messagesHandler.obtainMessage(ConversationsActivity.START_CONVERSATION);
Bundle bundle = new Bundle();
bundle.putString(DeviceListActivity.EXTRA_DEVICE_NAME, remoteDevice.getName());
bundle.putString(DeviceListActivity.EXTRA_DEVICE_ADDRESS, remoteDevice.getAddress());
Log.e(TAG, "address = " + DeviceListActivity.EXTRA_DEVICE_ADDRESS + remoteDevice.getAddress() + " Name = " + DeviceListActivity.EXTRA_DEVICE_NAME + remoteDevice.getName());
msg.setData(bundle);
messagesHandler.sendMessage(msg);
}
setState(STATE_CONNECTED);
Log.d(TAG, "Message state change");
messagesHandler.obtainMessage(BluetoothChatActivity.MESSAGE_STATE_CHANGE, currentState, -1).sendToTarget();
}
}
/*
* This method stops all of the threads
*/
public synchronized void stop()
{
Log.d(TAG, "stop");
if (connectThread != null)
{
connectThread.cancel();
connectThread = null;
}
if (acceptThread != null)
{
acceptThread.cancel();
acceptThread = null;
}
messagesHandler.obtainMessage(BluetoothChatActivity.MESSAGE_CANCEL_CONNECTION).sendToTarget();
// TODO: continue with the connected thread
setState(STATE_NONE);
}
/*
* This method indicates that the connection to the device has failed and it notifies the UI activity
*/
public void connectionFailed()
{
Log.d(TAG, "connectionFailed");
// Send a failure message back to the Activity
setState(STATE_NONE);
messagesHandler.obtainMessage(BluetoothChatActivity.MESSAGE_STATE_CHANGE, currentState, -1).sendToTarget();
Message failedMsg = messagesHandler.obtainMessage(BluetoothChatActivity.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(BluetoothChatActivity.TOAST, "Unable to connect devices");
failedMsg.setData(bundle);
messagesHandler.sendMessage(failedMsg);
// Start the service over to restart listening mode
BluetoothChatService.this.start();
setState(STATE_NONE);
}
/*
* This method indicates that the connection to the device has failed and it notifies the UI activity
*/
public void connectionLost()
{
Log.d(TAG, "connectionLost");
// Send a failure message back to the activity
setState(STATE_NONE);
//messagesHandler.obtainMessage(BluetoothChatActivity.MESSAGE_STATE_CHANGE, currentState, -1).sendToTarget();
Message lostMsg = messagesHandler.obtainMessage(BluetoothChatActivity.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(BluetoothChatActivity.TOAST, "Device connection was lost");
lostMsg.setData(bundle);
messagesHandler.sendMessage(lostMsg);
// Start the service over to restart listening mode
BluetoothChatService.this.start();
}
public void write(byte[] out) {
Log.d(TAG, "Write()");
// Create temporary object
ConnectedThread tmp;
// Synchronize a copy of the ConnectedThread
synchronized (this) {
if (currentState != STATE_CONNECTED)
return;
tmp = connectedThread;
}
// Perform the write unsynchronized
tmp.write(out);
}
/*
* This thread runs while listening for incoming connections. It behaves
* like a server-side client. It runs until a connection is accepted (or
* until cancelled).
*/
private class AcceptThread extends Thread
{
// The local server socket
private final BluetoothServerSocket bluetoothServerSocket;
private String socketType;
public AcceptThread()
{
// A temporary object that later will be assigned to bluetoothServerSocket,
// Because it is final
BluetoothServerSocket tmpSocket = null;
try
{
tmpSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, APP_UUID);
}
catch (IOException e)
{
Log.e("Failed", "Temp server");
}
finally
{
bluetoothServerSocket = tmpSocket;
}
}
@Override
public void run() {
// TODO Auto-generated method stub
BluetoothSocket bluetoothSocket = null;
setName("AcceptThread" + socketType);
// Keep listening until exception occurs or a socket is returned
while (true)
{
try
{
bluetoothSocket = bluetoothServerSocket.accept();
}
catch (IOException e)
{
Log.e("FAILED", "Socket Type: " + bluetoothSocket
+ "accept() failed");
break;
}
// If a connection was accepted
if (bluetoothSocket != null)
{
// Do work to manage the connection (in a separate thread)
synchronized (BluetoothChatService.this)
{
switch (currentState)
{
case STATE_LISTEN:
case STATE_CONNECTING:
// Situation normal. Start the connected thread.
Log.e(TAG, "Calling connected");
connected(bluetoothSocket, bluetoothSocket.getRemoteDevice(), socketType);
break;
case STATE_NONE:
case STATE_CONNECTED:
// Either not ready or already connected. Terminate
// new socket.
try
{
bluetoothSocket.close();
}
catch (IOException e)
{
Log.e("FAILED", "Could not close unwanted socket");
}
break;
}
}
}
}
}
/* Will cancel the listening socket, and cause the thread to finish */
public void cancel() {
try {
bluetoothServerSocket.close();
} catch (IOException e) { }
}
}
/*
* 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 bluetoothSocket;
private final BluetoothDevice remoteDevice;
private String socketType;
public ConnectThread(BluetoothDevice remoteDevice)
{
this.remoteDevice = remoteDevice;
// Use a temporary object that is later assigned to bluetoothSocket,
// because mmSocket is final
BluetoothSocket tmp = null;
// 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 = remoteDevice.createRfcommSocketToServiceRecord(APP_UUID);
Log.d(TAG, tmp.getRemoteDevice().getAddress());
}
catch (IOException e)
{
Log.e("FAILED", "RFC Comm");
}
bluetoothSocket = tmp;
}
@Override
public void run() {
// Cancel discovery because it will slow down the connection
bluetoothAdapter.cancelDiscovery();
try
{
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
bluetoothSocket.connect();
}
catch (IOException connectException)
{
// Unable to connect; close the socket and get out
try
{
bluetoothSocket.close();
}
catch (IOException closeException)
{
Log.e("FAILED", "Connect");
}
connectionFailed();
return;
}
// Reset the ConnectThread because we're done
synchronized (BluetoothChatService.this)
{
connectThread = null;
}
// Start the connected thread
Log.e(TAG, "Calling connected");
connected(bluetoothSocket, remoteDevice, socketType);
}
public void cancel() {
try {
bluetoothSocket.close();
} catch (IOException e) { }
}
}
private class ConnectedThread extends Thread
{
private final BluetoothSocket bluetoothSocket;
private final InputStream chatInputStream;
private final OutputStream chatOutputStream;
public ConnectedThread(BluetoothSocket connectedSocket, String socketType)
{
this.bluetoothSocket = connectedSocket;
InputStream tmpInputStream = null;
OutputStream tmpOutputStream = null;
// Get the bluetooth socket input and output streams
try
{
tmpInputStream = bluetoothSocket.getInputStream();
tmpOutputStream = bluetoothSocket.getOutputStream();
}
catch (IOException e)
{
Log.e(TAG, "Connected Thread Constructor");
}
chatInputStream = tmpInputStream;
chatOutputStream = tmpOutputStream;
}
@Override
public void run() {
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true)
{
try
{
// Read from input stream
bytes = chatInputStream.read(buffer);
Log.d(TAG, "MESSAGE_READ");
// Send the obtained bytes to the UI Activity
messagesHandler.obtainMessage(BluetoothChatActivity.MESSAGE_READ, bytes, -1, buffer).sendToTarget();
Log.d(TAG, "Message read has sent by handler");
}
catch (IOException e)
{
Log.e(TAG, "disconnected", e);
BluetoothChatService.this.stop();
connectionLost();
// Start the service over to restart listening mode
break;
}
}
}
public void write(byte[] buffer) {
try {
chatOutputStream.write(buffer);
// Share the sent message back to the UI Activity
messagesHandler.obtainMessage(BluetoothChatActivity.MESSAGE_WRITE, -1, -1, buffer).sendToTarget();
} catch (IOException e) {
Log.e("Failed", "Exception during write");
}
}
public void cancel() {
try {
bluetoothSocket.close();
} catch (IOException e) {
Log.e("Failed", "close() of connect socket failed", e);
}
}
}
}
答案 0 :(得分:0)
好吧,经过多次尝试后我意识到了问题 - 聊天服务实例化了两次,所以我把它变成了单身。