问题
Have a problem while developing an app based in the BluetoothChat example, but divided in 2 activities.
- The main with bluetooth actions ()BTActivity
- The chat (BTCommunication)
I have the BluetoothChatService too divided in the following files, but they aren't activities:
- Transmission: All the Handler actions
- ConnectThread
- ConnectedThread
- AccpetThread
The app finds de device, starts connecting it and then crashes. I'm trying to find out what i'm doing wrong comparing with the BluetoothChat App, but i don't find the problem.
07-23 10:58:43.076: D/AbsListView(17279): unregisterIRListener() is called
07-23 10:58:43.076: D/AbsListView(17279): unregisterIRListener() is called
07-23 10:58:43.086: D/BluetoothUtils(17279): isSocketAllowedBySecurityPolicy start : device null
07-23 10:58:43.086: W/BluetoothAdapter(17279): getBluetoothService() called with no BluetoothManagerCallback
07-23 10:58:43.106: E/SpannableStringBuilder(17279): SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
07-23 10:58:43.106: E/SpannableStringBuilder(17279): SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
07-23 10:58:43.116: D/AbsListView(17279): onDetachedFromWindow
07-23 10:58:43.116: D/AbsListView(17279): unregisterIRListener() is called
07-23 10:58:43.116: D/AbsListView(17279): onDetachedFromWindow
07-23 10:58:43.116: D/AbsListView(17279): unregisterIRListener() is called
07-23 10:58:44.527: D/AndroidRuntime(17279): Shutting down VM
07-23 10:58:44.527: W/dalvikvm(17279): threadid=1: thread exiting with uncaught exception (group=0x41d58ac8)
07-23 10:58:44.537: E/AndroidRuntime(17279): FATAL EXCEPTION: main
07-23 10:58:44.537: E/AndroidRuntime(17279): java.lang.NullPointerException
07-23 10:58:44.537: E/AndroidRuntime(17279): at com.example.btaplication.BTActivity$1.handleMessage(BTActivity.java:288)
07-23 10:58:44.537: E/AndroidRuntime(17279): at android.os.Handler.dispatchMessage(Handler.java:99)
07-23 10:58:44.537: E/AndroidRuntime(17279): at android.os.Looper.loop(Looper.java:137)
07-23 10:58:44.537: E/AndroidRuntime(17279): at android.app.ActivityThread.main(ActivityThread.java:5328)
07-23 10:58:44.537: E/AndroidRuntime(17279): at java.lang.reflect.Method.invokeNative(Native Method)
07-23 10:58:44.537: E/AndroidRuntime(17279): at java.lang.reflect.Method.invoke(Method.java:511)
07-23 10:58:44.537: E/AndroidRuntime(17279): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1102)
07-23 10:58:44.537: E/AndroidRuntime(17279): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869)
07-23 10:58:44.537: E/AndroidRuntime(17279): at dalvik.system.NativeStart.main(Native Method)
07-23 10:58:55.428: I/Process(17279): Sending signal. PID: 17279 SIG: 9
/ Here the Main activity
public class BTActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Button button1 = (Button) findViewById(R.id.boton1);
final Button button2 = (Button) findViewById(R.id.boton2);
final Button button4 = (Button) findViewById(R.id.boton4);
final Button button5 = (Button) findViewById(R.id.boton5);
button5.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
lanzarComunicacion (null);
}
});
GlobalVar.mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (GlobalVar.mBluetoothAdapter == null) {
Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show();
finish();
return;
}
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LanzarBusqueda(null);
}
});
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!GlobalVar.mBluetoothAdapter.isDiscovering()) {
Context context = getApplicationContext();
CharSequence text = "MAKING YOUR DEVICE DISCOVERABLE";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
}
}
});
button4.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
GlobalVar.mBluetoothAdapter.disable();
Context context = getApplicationContext();
CharSequence text = "TURNING OFF BLUETOOTH";
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, text, 15);
toast.show();
}
});
}
@Override
public void onStart() {
super.onStart();
if (!GlobalVar.mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, GlobalVar.REQUEST_ENABLE_BT);
}
else {
if (GlobalVar.mTransmission == null) setupCaller();
}
}
@Override
public void onResume() {
super.onResume();
if (GlobalVar.mTransmission != null) {
/**Only if the state is STATE_NONE, do we know that we haven't started already*/
if (GlobalVar.mTransmission.getState() == GlobalVar.STATE_NONE) {
}
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case GlobalVar.REQUEST_CONNECT_DEVICE:
/**When DeviceListActivity returns with a device to connect*/
if (resultCode == Activity.RESULT_OK) {
connectDevice(data);
}
case GlobalVar.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*/
setupCaller();
} else {
/**User did not enable Bluetooth or an error occurred*/
Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();
finish();
}
break;
}
}
private void connectDevice(Intent data) {
/**Get the device MAC address*/
String address = data.getExtras().getString(DeviceListDialog.EXTRA_DEVICE_ADDRESS);
/**Get the BluetoothDevice object*/
BluetoothDevice device = GlobalVar.mBluetoothAdapter.getRemoteDevice(address);
/**Attempt to connect to the device*/
try{
GlobalVar.mTransmission.connect(device);
}catch(Exception ex) {
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
/**Inflate the menu; this adds items to the action bar if it is present.*/
getMenuInflater().inflate(R.menu.bt, menu);
return true;
}
public void lanzarComunicacion (View view) {
Intent i = new Intent(this, BTCommunication.class);
startActivity(i);
}
public void LanzarBusqueda (View view) {
Intent serverintent = new Intent(this, DeviceListDialog.class);
startActivityForResult(serverintent, GlobalVar.REQUEST_CONNECT_DEVICE);
}
private final void setStatus(int resId) {
final ActionBar actionBar = getActionBar();
actionBar.setSubtitle(resId);
}
private final void setStatus(CharSequence subTitle) {
final ActionBar actionBar = getActionBar();
actionBar.setSubtitle(subTitle);
}
/**
* The Handler that gets information back from the Transmission
*/
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case GlobalVar.MESSAGE_STATE_CHANGE:
switch (msg.arg1) {
case GlobalVar.STATE_CONNECTED:
setStatus(getString(R.string.title_connected_to, GlobalVar.mConnectedDeviceName));
GlobalVar.mConversationArrayAdapter.clear();
break;
case GlobalVar.STATE_CONNECTING:
setStatus(R.string.title_connecting);
break;
case GlobalVar.STATE_LISTEN:
case GlobalVar.STATE_NONE:
setStatus(R.string.title_not_connected);
break;
}
break;
case GlobalVar.MESSAGE_WRITE:
byte[] writeBuf = (byte[]) msg.obj;
/**construct a string from the buffer*/
String writeMessage = new String(writeBuf);
GlobalVar.mConversationArrayAdapter.add("Me: " + writeMessage);
break;
case GlobalVar.MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
/**construct a string from the valid bytes in the buffer*/
String readMessage = new String(readBuf, 0, msg.arg1);
GlobalVar.mConversationArrayAdapter.add(GlobalVar.mConnectedDeviceName+": " + readMessage);
break;
case GlobalVar.MESSAGE_DEVICE_NAME:
/**save the connected device's name*/
GlobalVar.mConnectedDeviceName = msg.getData().getString(GlobalVar.DEVICE_NAME);
Toast.makeText(getApplicationContext(), "Connected to " + GlobalVar.mConnectedDeviceName, Toast.LENGTH_SHORT).show();
break;
case GlobalVar.MESSAGE_TOAST:
Toast.makeText(getApplicationContext(), msg.getData().getString(GlobalVar.TOAST), Toast.LENGTH_SHORT).show();
break;
}
}
};
public void setupCaller() {
/**Initialize the Transmission to perform bluetooth connections*/
GlobalVar.mTransmission = new Transmission(this, mHandler);
}
}
/ The Chat Avtivity
public class BTCommunication extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/**Set up the window layout*/
setContentView(R.layout.chat);
/**Start the Bluetooth chat services*/
GlobalVar.mTransmission.start();
setupChat(); //PROBAMOS A LLAMAR AQUI\\
}
public void setupChat() {
/**Initialize the array adapter for the conversation thread*/
GlobalVar.mConversationArrayAdapter = new ArrayAdapter<String>(this, R.layout.message);
GlobalVar.mConversationView = (ListView) findViewById(R.id.in);
GlobalVar.mConversationView.setAdapter(GlobalVar.mConversationArrayAdapter);
/**Initialize the compose field with a listener for the return key*/
GlobalVar.mOutEditText = (EditText) findViewById(R.id.edit_text_out);
GlobalVar.mOutEditText.setOnEditorActionListener(mWriteListener);
/**Initialize the send button with a listener that for click events*/
GlobalVar.mSendButton = (Button) findViewById(R.id.button_send);
GlobalVar.mSendButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
/**Send a message using content of the edit text widget*/
TextView view = (TextView) findViewById(R.id.edit_text_out);
String message = view.getText().toString();
sendMessage(message);
}
});
/**Initialize the Transmission to perform bluetooth connections*/
//Done it in BTActivity in the function "setupCaller()"\\
/**Initialize the buffer for outgoing messages*/
GlobalVar.mOutStringBuffer = new StringBuffer("");
}
@Override
public void onDestroy() {
super.onDestroy();
/**Stop the Bluetooth chat services*/
if (GlobalVar.mTransmission != null) GlobalVar.mTransmission.stop();
}
/**
* Sends a message.
* @param message A string of text to send.
*/
public void sendMessage(String message) {
/**Check that we're actually connected before trying anything*/
if (GlobalVar.mTransmission.getState() != GlobalVar.STATE_CONNECTED) {
Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT).show();
return;
}
/**Check that there's actually something to send*/
if (message.length() > 0) {
/**Get the message bytes and tell the BluetoothChatService to write*/
byte[] send = message.getBytes();
GlobalVar.mTransmission.write(send);
/**Reset out string buffer to zero and clear the edit text field*/
GlobalVar.mOutStringBuffer.setLength(0);
GlobalVar. mOutEditText.setText(GlobalVar.mOutStringBuffer);
}
}
/**The action listener for the EditText widget, to listen for the return key*/
private final TextView.OnEditorActionListener mWriteListener = new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
/**If the action is a key-up event on the return key, send the message*/
if (actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_UP) {
String message = view.getText().toString();
sendMessage(message);
}
return true;
}
};
}
/The Transmission file:
public class Transmission {
/**
* Constructor. Prepares a new session.
* @param context The UI Activity Context
* @param handler A Handler to send messages back to the UI Activity
*/
public Transmission(Context context, Handler handler) {
GlobalVar.mAdapter = BluetoothAdapter.getDefaultAdapter();
GlobalVar.mState = GlobalVar.STATE_NONE;
GlobalVar.mHandler = handler;
}
/**
* Set the current state of the connection
* @param state An integer defining the current connection state
*/
public synchronized void setState(int state) {
GlobalVar.mState = state;
/**Give the new state to the Handler so the UI Activity can update*/
GlobalVar.mHandler.obtainMessage(GlobalVar.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
}
/**
* Return the current connection state.
*/
public synchronized int getState() {
return GlobalVar.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() {
/**Cancel any thread attempting to make a connection*/
if (GlobalVar.mConnectThread != null) {GlobalVar.mConnectThread.cancel(); GlobalVar.mConnectThread = null;}
/**Cancel any thread currently running a connection*/
if (GlobalVar.mConnectedThread != null) {GlobalVar.mConnectedThread.cancel(); GlobalVar.mConnectedThread = null;}
setState(GlobalVar.STATE_LISTEN);
/**Start the thread to listen on a BluetoothServerSocket*/
if (GlobalVar.mAcceptThread == null) {
GlobalVar.mAcceptThread = new AcceptThread();
GlobalVar.mAcceptThread.start();
}
}
/**
* Start the ConnectThread to initiate a connection to a remote device.
* @param device The BluetoothDevice to connect
*/
public synchronized void connect(BluetoothDevice device) {
/**Cancel any thread attempting to make a connection*/
if (GlobalVar.mState == GlobalVar.STATE_CONNECTING) {
if (GlobalVar.mConnectThread != null) {GlobalVar.mConnectThread.cancel(); GlobalVar.mConnectThread = null;}
}
/**Cancel any thread currently running a connection*/
if (GlobalVar.mConnectedThread != null) {GlobalVar.mConnectedThread.cancel(); GlobalVar.mConnectedThread = null;}
/**Start the thread to connect with the given device*/
GlobalVar.mConnectThread = new ConnectThread(device);
GlobalVar.mConnectThread.start();
setState(GlobalVar.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 (GlobalVar.mConnectThread != null) {GlobalVar.mConnectThread.cancel(); GlobalVar.mConnectThread = null;}
/**Cancel any thread currently running a connection*/
if (GlobalVar.mConnectedThread != null) {GlobalVar.mConnectedThread.cancel(); GlobalVar.mConnectedThread = null;}
/**Cancel the accept thread because we only want to connect to one device*/
if (GlobalVar.mAcceptThread != null) {
GlobalVar.mAcceptThread.cancel();
GlobalVar.mAcceptThread = null;
}
/**Start the thread to manage the connection and perform transmissions*/
GlobalVar.mConnectedThread = new ConnectedThread(socket);
GlobalVar.mConnectedThread.start();
/**Send the name of the connected device back to the UI Activity*/
Message msg = GlobalVar.mHandler.obtainMessage(GlobalVar.MESSAGE_DEVICE_NAME);
Bundle bundle = new Bundle();
bundle.putString(GlobalVar.DEVICE_NAME, device.getName());
msg.setData(bundle);
GlobalVar.mHandler.sendMessage(msg);
setState(GlobalVar.STATE_CONNECTED);
}
/**
* Stop all threads
*/
public synchronized void stop() {
if (GlobalVar.mConnectThread != null) {
GlobalVar.mConnectThread.cancel();
GlobalVar.mConnectThread = null;
}
if (GlobalVar.mConnectedThread != null) {
GlobalVar.mConnectedThread.cancel();
GlobalVar.mConnectedThread = null;
}
if (GlobalVar.mAcceptThread != null) {
GlobalVar.mAcceptThread.cancel();
GlobalVar.mAcceptThread = null;
}
setState(GlobalVar.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 (GlobalVar.mState != GlobalVar.STATE_CONNECTED) return;
r = GlobalVar.mConnectedThread;
}
/**Perform the write unsynchronized*/
r.write(out);
}
/**
* Indicate that the connection attempt failed and notify the UI Activity.
*/
public void connectionFailed() {
/**Send a failure message back to the Activity*/
Message msg = GlobalVar.mHandler.obtainMessage(GlobalVar.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(GlobalVar.TOAST, "Unable to connect device");
msg.setData(bundle);
GlobalVar.mHandler.sendMessage(msg);
/**tart the service over to restart listening mode*/
Transmission.this.start();
}
/**
* Indicate that the connection was lost and notify the UI Activity.
*/
public void connectionLost() {
/**Send a failure message back to the Activity*/
Message msg = GlobalVar.mHandler.obtainMessage(GlobalVar.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(GlobalVar.TOAST, "Device connection was lost");
msg.setData(bundle);
GlobalVar.mHandler.sendMessage(msg);
/**Start the service over to restart listening mode*/
Transmission.this.start();
}
}
/The Accept, connect and connected threads are the same as in BleutoothChat app but each one has it's own file.
回答1:
07-23 10:58:44.537: E/AndroidRuntime(17279): at com.example.btaplication.BTActivity$1.handleMessage(BTActivity.java:288)
You need more condition in your Handler. It crashes because you have a null pointer in your BTActivity.
I exactly had this problem 2 weeks ago (I was trying to change text of a textview in a Handler). So, in my Handler I just put :
if(mTextView == null) {mTextView = (TextView) findViewById(R.id.tv)}
even if mTextView was define before. In that case you will be sure that your attribute is define, and you will avoid NPE
Hope it helps
来源:https://stackoverflow.com/questions/17806069/bluetoothchat-like-app-not-communicating