在我的蓝牙课程中遇到奇怪的 NPE,以前没有发生过
使用 Android 的蓝牙聊天示例应用程序作为我的指南 http://developer.android.com /resources/samples/BluetoothChat/index.html,我尝试为我正在开发的应用程序创建自己的蓝牙功能。
昨晚我用两部Android手机进行了测试,出现了一些问题,但没有强制关闭。当我要求它连接时,它根本没有连接我的设备。我进去添加了几行日志,以确保程序遵循正确的路线。今天,当我在手机上重新安装并启动该应用程序时,在尝试打开蓝牙时遇到强制关闭错误,而昨晚我根本没有遇到这个问题。我更改的唯一代码是添加了 2-3 个日志命令。我检查了 logcat 并得到以下内容:
作为你可以看到,问题是由 NPE @ line 185 引起的。这是我的 BluetoothService 类的代码,我将在下面重新发布问题的具体区域。
package com.tagapp.android;
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.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
public class BluetoothService {
private static final String TAG = "BluetoothService";
private static final boolean D = true;
private static final String NAME = "BluetoothTag";
private static final UUID MY_UUID =
UUID.fromString("93845760-234e-11e0-ac64-0800200c9a66");
private final BluetoothAdapter mAdapter;
private final Handler mHandler;
private AcceptThread mAcceptThread;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private int mState;
public static final int STATE_NONE = 0;
public static final int STATE_LISTEN = 1;
public static final int STATE_CONNECTING = 2;
public static final int STATE_CONNECTED = 3;
public BluetoothService(Context context, Handler handler) {
mAdapter = BluetoothAdapter.getDefaultAdapter();
mState = STATE_NONE;
mHandler = handler;
}
private synchronized void setState(int state) {
if (D) Log.d(TAG, "setState() " + mState + " -> " + state);
mState = state;
mHandler.obtainMessage(BluetoothTransfer.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
}
public synchronized int getState() {
return mState;
}
public synchronized void start() {
if (D) Log.d(TAG, "start");
if(mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if(mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
if(mAcceptThread == null) {
mAcceptThread = new AcceptThread();
mAcceptThread.start();
}
setState(STATE_LISTEN);
}
public synchronized void connect(BluetoothDevice device) {
if (D) Log.d(TAG, "connect to: " + device);
if(mState == STATE_CONNECTING) {
if(mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
}
if(mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
mConnectThread = new ConnectThread(device);
mConnectThread.start();
setState(STATE_CONNECTING);
}
public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
if (D) Log.d(TAG, "connected");
if(mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if(mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
if(mAcceptThread != null) {
mAcceptThread.cancel();
mAcceptThread = null;
}
mConnectedThread = new ConnectedThread(socket);
mConnectedThread.start();
Message msg = mHandler.obtainMessage(BluetoothTransfer.MESSAGE_DEVICE_NAME);
Bundle bundle = new Bundle();
bundle.putString(BluetoothTransfer.DEVICE_NAME, device.getName());
msg.setData(bundle);
mHandler.sendMessage(msg);
setState(STATE_CONNECTED);
}
public synchronized void stop() {
if (D) Log.d(TAG, "stop");
if(mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if(mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
if(mAcceptThread != null) {
mAcceptThread.cancel();
mAcceptThread = null;
}
setState(STATE_NONE);
}
public void write(byte[] out) {
ConnectedThread ct;
synchronized(this) {
if(mState != STATE_CONNECTED) return;
ct = mConnectedThread;
}
ct.write(out);
}
private void connectionFailed() {
setState(STATE_LISTEN);
Message msg = mHandler.obtainMessage(BluetoothTransfer.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(BluetoothTransfer.TOAST, "Unable to connect device");
msg.setData(bundle);
mHandler.sendMessage(msg);
}
private void connectionLost() {
setState(STATE_LISTEN);
Message msg = mHandler.obtainMessage(BluetoothTransfer.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(BluetoothTransfer.TOAST, "Device connection was lost");
msg.setData(bundle);
mHandler.sendMessage(msg);
}
private class AcceptThread extends Thread {
private final BluetoothServerSocket mmServerSocket;
public AcceptThread() {
BluetoothServerSocket tmp = null;
try {
tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
}
catch (IOException e) {
Log.e(TAG, "listen() failed", e);
}
mmServerSocket = tmp;
}
public void run() {
if (D) Log.d(TAG, "BEGIN mAcceptThread" + this);
setName("AcceptThread");
BluetoothSocket socket = null;
while (mState != STATE_CONNECTED) {
try {
socket = mmServerSocket.accept();
}
catch (IOException e) {
Log.e(TAG, "accept() failed", e);
break;
}
if(socket != null) {
synchronized (BluetoothService.this) {
switch(mState) {
case STATE_LISTEN :
case STATE_CONNECTING :
connected(socket, socket.getRemoteDevice());
break;
case STATE_NONE :
case STATE_CONNECTED :
try {
socket.close();
}
catch (IOException e) {
Log.e(TAG, "Could not close unwanted socket", e);
}
break;
}
}
}
}
if (D) Log.i(TAG, "END mAcceptThread");
}
public void cancel() {
if (D) Log.d(TAG, "cancel " + this);
try {
mmServerSocket.close();
}
catch (IOException e) {
Log.e(TAG, "close() of server failed", e);
}
}
}
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
mmDevice = device;
BluetoothSocket tmp = null;
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");
mAdapter.cancelDiscovery();
try {
mmSocket.connect();
}
catch (IOException e) {
connectionFailed();
try {
mmSocket.close();
}
catch (IOException e2) {
Log.e(TAG, "unable to close() socket during connection failure", e2);
}
BluetoothService.this.start();
return;
}
synchronized (BluetoothService.this) {
mConnectThread = null;
}
connected(mmSocket, mmDevice);
}
public void cancel() {
try {
mmSocket.close();
}
catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
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;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
}
catch (IOException e) {
Log.e(TAG, "tempt sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int bytes;
while (true) {
try {
bytes = mmInStream.read(buffer);
mHandler.obtainMessage(BluetoothTransfer.CONTACT_RECEIVE, bytes, -1, buffer).sendToTarget();
}
catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
break;
}
}
}
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
mHandler.obtainMessage(BluetoothTransfer.CONTACT_SEND, -1, -1, buffer).sendToTarget();
}
catch (IOException e) {
Log.e(TAG, "exception during write", e);
}
}
public void cancel() {
try {
mmSocket.close();
}
catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
}
导致NPE(AcceptThread)的行:
private class AcceptThread extends Thread {
private final BluetoothServerSocket mmServerSocket;
public AcceptThread() {
BluetoothServerSocket tmp = null;
try {
tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
}
catch (IOException e) {
Log.e(TAG, "listen() failed", e);
}
mmServerSocket = tmp;
}
public void run() {
if (D) Log.d(TAG, "BEGIN mAcceptThread" + this);
setName("AcceptThread");
BluetoothSocket socket = null;
while (mState != STATE_CONNECTED) {
try {
socket = mmServerSocket.accept();//THIS LINE CAUSES NPE
}
catch (IOException e) {
Log.e(TAG, "accept() failed", e);
break;
}
对象套接字应该初始化@ null,但应该尝试socket = mmServerSocket.accept();
这直接来自 Android 开发网站上提供的 Google 示例应用程序。我有两个问题:1,为什么这不起作用,2,为什么几个小时前它还工作得很好?
感谢您的帮助。
Using Android's Bluetooth Chat sample app as my guide http://developer.android.com/resources/samples/BluetoothChat/index.html, I've tried to create my own bluetooth function for an app I am working on.
Last night I tested it with two Android phones and had some issues, but there were no force closes. It simply didn't connect my devices when I asked it to. I went in and added a few Log lines to make sure the program was following the proper course. When I reinstalled and launched the app on my phone today, I got a force close error when attempting to turn on Bluetooth, a problem I did not have at all last night. The only code I changed was the addition of 2-3 log commands. I checked logcat and got the following:
As you can see, the problem is caused by an NPE @ line 185. Here is my code for the BluetoothService class, I will repost the specific area of issue below it.
package com.tagapp.android;
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.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
public class BluetoothService {
private static final String TAG = "BluetoothService";
private static final boolean D = true;
private static final String NAME = "BluetoothTag";
private static final UUID MY_UUID =
UUID.fromString("93845760-234e-11e0-ac64-0800200c9a66");
private final BluetoothAdapter mAdapter;
private final Handler mHandler;
private AcceptThread mAcceptThread;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private int mState;
public static final int STATE_NONE = 0;
public static final int STATE_LISTEN = 1;
public static final int STATE_CONNECTING = 2;
public static final int STATE_CONNECTED = 3;
public BluetoothService(Context context, Handler handler) {
mAdapter = BluetoothAdapter.getDefaultAdapter();
mState = STATE_NONE;
mHandler = handler;
}
private synchronized void setState(int state) {
if (D) Log.d(TAG, "setState() " + mState + " -> " + state);
mState = state;
mHandler.obtainMessage(BluetoothTransfer.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
}
public synchronized int getState() {
return mState;
}
public synchronized void start() {
if (D) Log.d(TAG, "start");
if(mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if(mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
if(mAcceptThread == null) {
mAcceptThread = new AcceptThread();
mAcceptThread.start();
}
setState(STATE_LISTEN);
}
public synchronized void connect(BluetoothDevice device) {
if (D) Log.d(TAG, "connect to: " + device);
if(mState == STATE_CONNECTING) {
if(mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
}
if(mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
mConnectThread = new ConnectThread(device);
mConnectThread.start();
setState(STATE_CONNECTING);
}
public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
if (D) Log.d(TAG, "connected");
if(mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if(mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
if(mAcceptThread != null) {
mAcceptThread.cancel();
mAcceptThread = null;
}
mConnectedThread = new ConnectedThread(socket);
mConnectedThread.start();
Message msg = mHandler.obtainMessage(BluetoothTransfer.MESSAGE_DEVICE_NAME);
Bundle bundle = new Bundle();
bundle.putString(BluetoothTransfer.DEVICE_NAME, device.getName());
msg.setData(bundle);
mHandler.sendMessage(msg);
setState(STATE_CONNECTED);
}
public synchronized void stop() {
if (D) Log.d(TAG, "stop");
if(mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if(mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
if(mAcceptThread != null) {
mAcceptThread.cancel();
mAcceptThread = null;
}
setState(STATE_NONE);
}
public void write(byte[] out) {
ConnectedThread ct;
synchronized(this) {
if(mState != STATE_CONNECTED) return;
ct = mConnectedThread;
}
ct.write(out);
}
private void connectionFailed() {
setState(STATE_LISTEN);
Message msg = mHandler.obtainMessage(BluetoothTransfer.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(BluetoothTransfer.TOAST, "Unable to connect device");
msg.setData(bundle);
mHandler.sendMessage(msg);
}
private void connectionLost() {
setState(STATE_LISTEN);
Message msg = mHandler.obtainMessage(BluetoothTransfer.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(BluetoothTransfer.TOAST, "Device connection was lost");
msg.setData(bundle);
mHandler.sendMessage(msg);
}
private class AcceptThread extends Thread {
private final BluetoothServerSocket mmServerSocket;
public AcceptThread() {
BluetoothServerSocket tmp = null;
try {
tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
}
catch (IOException e) {
Log.e(TAG, "listen() failed", e);
}
mmServerSocket = tmp;
}
public void run() {
if (D) Log.d(TAG, "BEGIN mAcceptThread" + this);
setName("AcceptThread");
BluetoothSocket socket = null;
while (mState != STATE_CONNECTED) {
try {
socket = mmServerSocket.accept();
}
catch (IOException e) {
Log.e(TAG, "accept() failed", e);
break;
}
if(socket != null) {
synchronized (BluetoothService.this) {
switch(mState) {
case STATE_LISTEN :
case STATE_CONNECTING :
connected(socket, socket.getRemoteDevice());
break;
case STATE_NONE :
case STATE_CONNECTED :
try {
socket.close();
}
catch (IOException e) {
Log.e(TAG, "Could not close unwanted socket", e);
}
break;
}
}
}
}
if (D) Log.i(TAG, "END mAcceptThread");
}
public void cancel() {
if (D) Log.d(TAG, "cancel " + this);
try {
mmServerSocket.close();
}
catch (IOException e) {
Log.e(TAG, "close() of server failed", e);
}
}
}
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
mmDevice = device;
BluetoothSocket tmp = null;
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");
mAdapter.cancelDiscovery();
try {
mmSocket.connect();
}
catch (IOException e) {
connectionFailed();
try {
mmSocket.close();
}
catch (IOException e2) {
Log.e(TAG, "unable to close() socket during connection failure", e2);
}
BluetoothService.this.start();
return;
}
synchronized (BluetoothService.this) {
mConnectThread = null;
}
connected(mmSocket, mmDevice);
}
public void cancel() {
try {
mmSocket.close();
}
catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
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;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
}
catch (IOException e) {
Log.e(TAG, "tempt sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int bytes;
while (true) {
try {
bytes = mmInStream.read(buffer);
mHandler.obtainMessage(BluetoothTransfer.CONTACT_RECEIVE, bytes, -1, buffer).sendToTarget();
}
catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
break;
}
}
}
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
mHandler.obtainMessage(BluetoothTransfer.CONTACT_SEND, -1, -1, buffer).sendToTarget();
}
catch (IOException e) {
Log.e(TAG, "exception during write", e);
}
}
public void cancel() {
try {
mmSocket.close();
}
catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
}
The lines which are causing the NPE (the AcceptThread):
private class AcceptThread extends Thread {
private final BluetoothServerSocket mmServerSocket;
public AcceptThread() {
BluetoothServerSocket tmp = null;
try {
tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
}
catch (IOException e) {
Log.e(TAG, "listen() failed", e);
}
mmServerSocket = tmp;
}
public void run() {
if (D) Log.d(TAG, "BEGIN mAcceptThread" + this);
setName("AcceptThread");
BluetoothSocket socket = null;
while (mState != STATE_CONNECTED) {
try {
socket = mmServerSocket.accept();//THIS LINE CAUSES NPE
}
catch (IOException e) {
Log.e(TAG, "accept() failed", e);
break;
}
The object socket should by initialized @ null, but it is supposed to try socket = mmServerSocket.accept();
This is directly from Google's sample app provided on the Android dev website. I have two concerns: 1, why isn't this working, and 2, why did it work just fine just hours ago?
Thanks for your help.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
关于“奇怪的NPE”——一点也不奇怪。在这一行得到 NPE 的原因
非常明显 - 变量 mmServerSocket 等于 NULL,这是在这行代码中得到 NPE 的唯一可能原因。 mmServerSocket 等于 NULL 的原因也很简单 - 查看类的构造函数:
您正在调用抛出 IOException 的方法
listenUsingRfcommWithServiceRecord
,您捕获了此异常,我们可以清楚地看到请参阅 logcat。接下来,tmp
变量保持初始化为NULL,与mmServerSocket
相同,这导致了上面提到的NPE。listenUsingRfcommWithServiceRecord
抛出 IOException 的原因 - 因为蓝牙已关闭,正如您在问题中提到的那样。 Android 文档没有说明您的假设,即如果蓝牙关闭,此方法应自动打开蓝牙。我认为您应该在调用listenUsingRfcommWithServiceRecord
之前手动检查蓝牙是否已关闭并手动打开。您可以了解如何检查蓝牙是否打开/关闭以及如何将其打开 此处和此处
Regarding "strange NPE" - it's not strange at all. The reason you get NPE at this line
is pretty obvious - variable mmServerSocket equals NULL, and this is the only possible reason to get NPE at this line of code. The reason why mmServerSocket equals NULL is simple too - look at a constructor of your class:
You are calling method
listenUsingRfcommWithServiceRecord
which throws IOException, you catching this exception, as we can clearly see in logcat. Next,tmp
variable stays initialized as NULL, same asmmServerSocket
, which leads as to NPE mentioned above.The reason why
listenUsingRfcommWithServiceRecord
is throwing IOException - because bluetooth is turned off, as you mention in your question. Android documentation says nothing about your assumption that this method should automatically turn on bluetooth if it's turned off. I think you should manually check if bluetooth is turned off and turn it on manually, before callinglistenUsingRfcommWithServiceRecord
.You can find how to check is bluetooth turned on/off and turn it on here and here