在向另一个蓝牙设备发送文本消息时获取StringIndexOutOfBoundsException

时间:2015-01-17 05:45:14

标签: java android bluetooth

我正在使用Android应用程序,我需要通过蓝牙发送文本。我已经想出了一段代码来实现这一点。我的问题是它在将消息发送到设备抛出StringIndexOutOfBoundsException后崩溃了。我该如何解决这个问题。我的完整代码是:

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)

1 个答案:

答案 0 :(得分:0)

在参考String类时,我们发现当出现以下三种情况之一时,调用String (byte[] data, int offset, int byteCount)会抛出IndexOutOfBoundsException

  1. offset > 0 - 如果传递给方法的偏移量小于0,则抛出Exception。由于您将0而不是变量传递给方法调用,因此不会导致Exception

  2. offset + byteCount > data.length - 在这种情况下,当Exceptionoffset大于缓冲区的长度时,将引发byteCount。在您的代码中,offset总是0byteCount,在您的示例中为bytesRead - 1,永远不会超过2048,因为instream.read(buffer)不能读取比buffer本身可以容纳的更多字节。这意味着offset(0)+ byteCount(-1≤byteCount≤2047)永远不会大于data.length(2048),所以这不是Exception

  3. byteCount < 0 - 当您传递小于Exception的{​​{1}}计数时,将抛出上述byte的第三种情况。在您的示例中,您将0作为bytesRead - 1计数传递。当您检查以确保byte(如果已到达流末尾时将会出现)时,您不会检查以确保至少读取了1 bytesRead != -1。这很可能是罪魁祸首...

  4. 根据您的示例,让我们考虑当byte返回bytesRead = instream.read(buffer);时会发生什么,这意味着没有读取0 ...

    1. 您执行的第一项检查byte将通过,因为if (bytesRead != -1)等于bytesRead

    2. 0语句中的内容if当然也会失败,因为while ((bytesRead == bufferSize) && (buffer[bufferSize - 1] != 0)) bytesRead不等于0 },这是bufferSize

    3. 最终通话为2048,我们可以将其转换为message = message + new String(buffer, 0, bytesRead - 1);。如您所见,由于message = message + String(buffer, 0, -1)为0,因此上述调用将生成bytesRead

    4. 要解决此问题,请确保在IndexOutOfBoundsException小于String(buffer, 0, bytesRead - 1)时不要致电bytesRead