向另一个蓝牙设备发送短信时获取 StringIndexOutOfBoundsException
Getting StringIndexOutOfBoundsException while sending text message to another bluetooth device
我正在开发一个 android 应用程序,我需要在其中通过蓝牙发送文本。我想出了一段代码来实现 this.My 问题是它在将消息发送到抛出 StringIndexOutOfBoundsException 的设备后崩溃了。我如何修复 this.My 完整代码是:
package com.example.blueremote;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.UUID;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity extends Activity {
private BluetoothAdapter btadapter;
private BluetoothSocket socket;
private Button btnSend;
private ArrayList<BluetoothDevice> foundDevices;
private ArrayAdapter<BluetoothDevice> aa;
private Handler handler = new Handler();
private ListView list;
private TextView tvmsg;
private static int DISCOVERY_REQUEST = 1;
private UUID uuid = UUID.fromString("a60f35f0-b93a-11de-8a39-08002009c666");
ImageButton up;
private String address = "D8:50:E6:8A:16:0F";
private String text = "up";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btadapter = BluetoothAdapter.getDefaultAdapter();
Intent disc;
disc = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
startActivityForResult(disc, DISCOVERY_REQUEST);
up = (ImageButton) findViewById(R.id.btn_up);
registerReceiver(discoveryResult, new IntentFilter(
BluetoothDevice.ACTION_FOUND));
AsyncTask<Integer, Void, Void> connectTask = new AsyncTask<Integer, Void, Void>() {
@Override
protected Void doInBackground(Integer... params) {
// TODO Auto-generated method stub
try {
Log.v("Main Activity", " AsyncTask started");
BluetoothDevice device = btadapter.getRemoteDevice(address);
socket = device.createRfcommSocketToServiceRecord(uuid);
Log.v("Main Activity", "Socket Created");
socket.connect();
Log.v("Main Activity", "Socket Connected");
} catch (IOException e) {
Log.d("BLUETOOTH_CLIENT", e.getMessage());
}
return null;
}
@Override
protected void onPostExecute(Void result) {
// Log.v("Main Activity", "Invoking switchUI");
// switchUI();
}
};
connectTask.execute();
up.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.v("Main Activity", "In up Button");
// Log.v("Main Activity", "Invoking switchUI");
switchUI();
}
});
}
private void switchUI() {
Log.v("Main Activity", "In SwitchUI Method");
Log.v("Main Activity", "Invoking sendMessage Method ");
sendMessage(socket, text);
Log.v("Main Activity", "Message Sent");
BluetoothSocketListener bsl = new BluetoothSocketListener(socket,
handler);
Thread messageListener = new Thread(bsl);
messageListener.start();
}
private void sendMessage(BluetoothSocket socket, String msg) {
msg = "UP";
OutputStream outStream;
try {
Log.v("Main Activity", "Inside sendMessage Method ");
outStream = socket.getOutputStream();
Log.v("Main Activity", "Outstream:" + outStream);
byte[] byteString = (msg + " ").getBytes();
Log.v("Main Activity", "byteString:" + byteString);
outStream.write(byteString);
Log.v("Main Activity", "outstream written:");
} catch (IOException e) {
Log.d("BLUETOOTH_COMMS", e.getMessage());
}
}
private class MessagePoster implements Runnable {
private TextView textView;
private String message;
public MessagePoster(String message) {
// this.textView = textView;
this.message = message;
}
public void run() {
// textView.setText(message);
}
}
private class BluetoothSocketListener implements Runnable {
private BluetoothSocket socket;
private TextView textView;
private Handler handler;
public BluetoothSocketListener(BluetoothSocket socket, Handler handler) {
this.socket = socket;
// this.textView = textView;
this.handler = handler;
}
public void run() {
int bufferSize = 2048;
byte[] buffer = new byte[bufferSize];
try {
InputStream instream = socket.getInputStream();
int bytesRead = -1;
String message = "";
while (true) {
message = "";
bytesRead = instream.read(buffer);
if (bytesRead != -1) {
while ((bytesRead == bufferSize)
&& (buffer[bufferSize - 1] != 0)) {
message = message
+ new String(buffer, 0, bytesRead);
bytesRead = instream.read(buffer);
}
message = message
+ new String(buffer, 0, bytesRead - 1);
handler.post(new MessagePoster(message));
socket.getInputStream();
}
}
} catch (IOException e) {
Log.d("BLUETOOTH_COMMS", e.getMessage());
}
}
}
BroadcastReceiver discoveryResult = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
BluetoothDevice remoteDevice;
remoteDevice = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (btadapter.getBondedDevices().contains(remoteDevice)) {
foundDevices.add(remoteDevice);
aa.notifyDataSetChanged();
}
}
};
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(discoveryResult);
}
}
Logcat:
E/AndroidRuntime(10360): FATAL EXCEPTION: Thread-1585
E/AndroidRuntime(10360): java.lang.StringIndexOutOfBoundsException: length=2048; regionStart=0; regionLength=65534
E/AndroidRuntime(10360): at java.lang.String.failedBoundsCheck(String.java:587)
E/AndroidRuntime(10360): at java.lang.String.<init>(String.java:247)
E/AndroidRuntime(10360): at java.lang.String.<init>(String.java:171)
E/AndroidRuntime(10360): at com.example.blueremote.MainActivity$BluetoothSocketListener.run(MainActivity.java:177)
参考 String
class,我们看到调用 String (byte[] data, int offset, int byteCount)
会在以下三种情况之一发生时抛出 IndexOutOfBoundsException
:
offset > 0
- 如果传递给方法的偏移量小于 0,将抛出 Exception
。由于您将 0
而不是变量传递给方法调用,因此这不会导致 Exception
.
offset + byteCount > data.length
- 在这种情况下,当 offset
加上 byteCount
大于缓冲区的长度时,将抛出 Exception
。在您的代码中,offset
始终是 0
和 byteCount
,在您的示例中是 bytesRead - 1
,永远不能超过 2048
,因为 instream.read(buffer)
不能读取比 buffer
本身可以容纳的更多字节。这意味着offset
(0)+byteCount
(-1≤byteCount
≤2047)永远不会大于data.length
(2048),所以这不是原因Exception
.
byteCount < 0
- 抛出上述 Exception
的第三种情况是当您传递的 byte
计数小于 0
时。在您的示例中,您将 bytesRead - 1
作为 byte
计数传递。当您检查以确保 bytesRead != -1
时,如果到达流的末尾就会发生这种情况,但您不检查以确保至少读取了 1 byte
。这很可能是罪魁祸首...
根据您的示例,让我们考虑当 bytesRead = instream.read(buffer);
returns 0
时会发生什么,这意味着没有 byte
被读取...
您执行的第一个检查 if (bytesRead != -1)
将通过,因为 bytesRead
等于 0
。
if
语句中的 while ((bytesRead == bufferSize) && (buffer[bufferSize - 1] != 0))
当然也会失败,因为 bytesRead
不等于 0
bufferSize
,也就是2048
.
最后的调用是message = message + new String(buffer, 0, bytesRead - 1);
,我们可以翻译成message = message + String(buffer, 0, -1)
。如您所见,由于 bytesRead
为 0,上述调用将生成 IndexOutOfBoundsException
.
要解决此问题,只需确保在 bytesRead
小于 1
时不调用 String(buffer, 0, bytesRead - 1)
。
我正在开发一个 android 应用程序,我需要在其中通过蓝牙发送文本。我想出了一段代码来实现 this.My 问题是它在将消息发送到抛出 StringIndexOutOfBoundsException 的设备后崩溃了。我如何修复 this.My 完整代码是:
package com.example.blueremote;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.UUID;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity extends Activity {
private BluetoothAdapter btadapter;
private BluetoothSocket socket;
private Button btnSend;
private ArrayList<BluetoothDevice> foundDevices;
private ArrayAdapter<BluetoothDevice> aa;
private Handler handler = new Handler();
private ListView list;
private TextView tvmsg;
private static int DISCOVERY_REQUEST = 1;
private UUID uuid = UUID.fromString("a60f35f0-b93a-11de-8a39-08002009c666");
ImageButton up;
private String address = "D8:50:E6:8A:16:0F";
private String text = "up";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btadapter = BluetoothAdapter.getDefaultAdapter();
Intent disc;
disc = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
startActivityForResult(disc, DISCOVERY_REQUEST);
up = (ImageButton) findViewById(R.id.btn_up);
registerReceiver(discoveryResult, new IntentFilter(
BluetoothDevice.ACTION_FOUND));
AsyncTask<Integer, Void, Void> connectTask = new AsyncTask<Integer, Void, Void>() {
@Override
protected Void doInBackground(Integer... params) {
// TODO Auto-generated method stub
try {
Log.v("Main Activity", " AsyncTask started");
BluetoothDevice device = btadapter.getRemoteDevice(address);
socket = device.createRfcommSocketToServiceRecord(uuid);
Log.v("Main Activity", "Socket Created");
socket.connect();
Log.v("Main Activity", "Socket Connected");
} catch (IOException e) {
Log.d("BLUETOOTH_CLIENT", e.getMessage());
}
return null;
}
@Override
protected void onPostExecute(Void result) {
// Log.v("Main Activity", "Invoking switchUI");
// switchUI();
}
};
connectTask.execute();
up.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.v("Main Activity", "In up Button");
// Log.v("Main Activity", "Invoking switchUI");
switchUI();
}
});
}
private void switchUI() {
Log.v("Main Activity", "In SwitchUI Method");
Log.v("Main Activity", "Invoking sendMessage Method ");
sendMessage(socket, text);
Log.v("Main Activity", "Message Sent");
BluetoothSocketListener bsl = new BluetoothSocketListener(socket,
handler);
Thread messageListener = new Thread(bsl);
messageListener.start();
}
private void sendMessage(BluetoothSocket socket, String msg) {
msg = "UP";
OutputStream outStream;
try {
Log.v("Main Activity", "Inside sendMessage Method ");
outStream = socket.getOutputStream();
Log.v("Main Activity", "Outstream:" + outStream);
byte[] byteString = (msg + " ").getBytes();
Log.v("Main Activity", "byteString:" + byteString);
outStream.write(byteString);
Log.v("Main Activity", "outstream written:");
} catch (IOException e) {
Log.d("BLUETOOTH_COMMS", e.getMessage());
}
}
private class MessagePoster implements Runnable {
private TextView textView;
private String message;
public MessagePoster(String message) {
// this.textView = textView;
this.message = message;
}
public void run() {
// textView.setText(message);
}
}
private class BluetoothSocketListener implements Runnable {
private BluetoothSocket socket;
private TextView textView;
private Handler handler;
public BluetoothSocketListener(BluetoothSocket socket, Handler handler) {
this.socket = socket;
// this.textView = textView;
this.handler = handler;
}
public void run() {
int bufferSize = 2048;
byte[] buffer = new byte[bufferSize];
try {
InputStream instream = socket.getInputStream();
int bytesRead = -1;
String message = "";
while (true) {
message = "";
bytesRead = instream.read(buffer);
if (bytesRead != -1) {
while ((bytesRead == bufferSize)
&& (buffer[bufferSize - 1] != 0)) {
message = message
+ new String(buffer, 0, bytesRead);
bytesRead = instream.read(buffer);
}
message = message
+ new String(buffer, 0, bytesRead - 1);
handler.post(new MessagePoster(message));
socket.getInputStream();
}
}
} catch (IOException e) {
Log.d("BLUETOOTH_COMMS", e.getMessage());
}
}
}
BroadcastReceiver discoveryResult = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
BluetoothDevice remoteDevice;
remoteDevice = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (btadapter.getBondedDevices().contains(remoteDevice)) {
foundDevices.add(remoteDevice);
aa.notifyDataSetChanged();
}
}
};
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(discoveryResult);
}
}
Logcat:
E/AndroidRuntime(10360): FATAL EXCEPTION: Thread-1585
E/AndroidRuntime(10360): java.lang.StringIndexOutOfBoundsException: length=2048; regionStart=0; regionLength=65534
E/AndroidRuntime(10360): at java.lang.String.failedBoundsCheck(String.java:587)
E/AndroidRuntime(10360): at java.lang.String.<init>(String.java:247)
E/AndroidRuntime(10360): at java.lang.String.<init>(String.java:171)
E/AndroidRuntime(10360): at com.example.blueremote.MainActivity$BluetoothSocketListener.run(MainActivity.java:177)
参考 String
class,我们看到调用 String (byte[] data, int offset, int byteCount)
会在以下三种情况之一发生时抛出 IndexOutOfBoundsException
:
offset > 0
- 如果传递给方法的偏移量小于 0,将抛出Exception
。由于您将0
而不是变量传递给方法调用,因此这不会导致Exception
.offset + byteCount > data.length
- 在这种情况下,当offset
加上byteCount
大于缓冲区的长度时,将抛出Exception
。在您的代码中,offset
始终是0
和byteCount
,在您的示例中是bytesRead - 1
,永远不能超过2048
,因为instream.read(buffer)
不能读取比buffer
本身可以容纳的更多字节。这意味着offset
(0)+byteCount
(-1≤byteCount
≤2047)永远不会大于data.length
(2048),所以这不是原因Exception
.byteCount < 0
- 抛出上述Exception
的第三种情况是当您传递的byte
计数小于0
时。在您的示例中,您将bytesRead - 1
作为byte
计数传递。当您检查以确保bytesRead != -1
时,如果到达流的末尾就会发生这种情况,但您不检查以确保至少读取了 1byte
。这很可能是罪魁祸首...
根据您的示例,让我们考虑当 bytesRead = instream.read(buffer);
returns 0
时会发生什么,这意味着没有 byte
被读取...
您执行的第一个检查
if (bytesRead != -1)
将通过,因为bytesRead
等于0
。if
语句中的while ((bytesRead == bufferSize) && (buffer[bufferSize - 1] != 0))
当然也会失败,因为bytesRead
不等于0
bufferSize
,也就是2048
.最后的调用是
message = message + new String(buffer, 0, bytesRead - 1);
,我们可以翻译成message = message + String(buffer, 0, -1)
。如您所见,由于bytesRead
为 0,上述调用将生成IndexOutOfBoundsException
.
要解决此问题,只需确保在 bytesRead
小于 1
时不调用 String(buffer, 0, bytesRead - 1)
。