InputStream无法通过蓝牙

时间:2017-07-18 07:06:38

标签: java android sockets bluetooth android-bluetooth

编辑1:MCVE -

我让我的整个代码都在主要问题中,但因为我被要求提供MCVE -

设备未接收其他已连接的Android设备发送给它的数据。代码未运行" inputStream.read(buffer)"因为没有数据可以接收。

发送数据的代码:

public void sendData(String s) throws IOException{
    byte[] byteString=s.getBytes();
    outputStream.write(byteString);
    outputStream.flush();
    Toast.makeText(getApplicationContext(), "Message sent", Toast.LENGTH_SHORT).show();
}

接收:

while (true){
            inputStream.read(buffer);
            final String str=new String(buffer);
            try{
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(context, str, Toast.LENGTH_SHORT).show();
                    }
                });
            }catch (Exception e){
                Toast.makeText(context, "Error in reading characters", Toast.LENGTH_SHORT).show();
            }
        }

另外,我这样连接了我的套接字:

Method method = bluetoothDevice.getClass().getMethod("createRfcommSocket", new Class[]{int.class});
bluetoothSocket = (BluetoothSocket) method.invoke(bluetoothDevice, 2);

使用端口号1或createRfCcommSocketToServiceRecord无效,因为连接失败。

整个问题:

我正在开发一个应用程序,我需要一个功能,通过蓝牙提供两个Android设备之间的双向通信。发送的数据将是简单的字符串。

我可以正确连接两台设备。这是我的代码:

 bluetoothAdapter=BluetoothAdapter.getDefaultAdapter();
    if(!bluetoothAdapter.isEnabled()){
        Intent intent= new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(intent,1);
    }

    pairedDevices=bluetoothAdapter.getBondedDevices();
    List<String> pairedDevicesList=new ArrayList<String>();
    if (pairedDevices.size() > 0) {
        for (BluetoothDevice device : pairedDevices) {
            pairedDevicesList.add(device.toString());
        }
    }

    listView.setVisibility(View.GONE);
    btListView.setVisibility(View.VISIBLE);
    btListView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, pairedDevicesList));

这将显示ListView上的所有配对设备。现在,在选择任何这些设备时,将使用以下连接进行连接:

try{
        btListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                try {
                    BluetoothDevice pairedDevicesArray[] = pairedDevices.toArray(new BluetoothDevice[pairedDevices.size()]);
                    bluetoothDevice = pairedDevicesArray[position];
                } catch (Exception e) {
                    Toast.makeText(getApplicationContext(), "Error in getting BT Device", Toast.LENGTH_SHORT).show();
                }

                try {
                    ParcelUuid parcelUuidArray[];
                    List<UUID> uuidList = new ArrayList<UUID>();
                    Class cl = Class.forName("android.bluetooth.BluetoothDevice");
                    Class[] params = {};
                    Method method = cl.getMethod("getUuids", params);
                    Object[] args = {};
                    parcelUuidArray = (ParcelUuid[]) method.invoke(bluetoothDevice, args);
                    for (ParcelUuid u : parcelUuidArray) {
                        uuidList.add(u.getUuid());
                    }
                    uuid = uuidList.get(0);
                    Toast.makeText(getApplicationContext(), uuid.toString(), Toast.LENGTH_SHORT).show();
                } catch (Exception e) {
                    Toast.makeText(getApplicationContext(), "Error in getting UUIDs", Toast.LENGTH_SHORT).show();
                }


                try {
                    Method method = bluetoothDevice.getClass().getMethod("createRfcommSocket", new Class[]{int.class});
                    bluetoothSocket = (BluetoothSocket) method.invoke(bluetoothDevice, 2);
                    //bluetoothSocket = bluetoothDevice.createRfcommSocketToServiceRecord(uuid);
                    Toast.makeText(getApplicationContext(), bluetoothSocket.toString(), Toast.LENGTH_SHORT).show();
                } catch (Exception e) {
                    Toast.makeText(getApplicationContext(), "Error in getting BT Socket", Toast.LENGTH_SHORT).show();
                }

                try {
                    bluetoothAdapter.cancelDiscovery();
                    if (!bluetoothSocket.isConnected()) {
                        bluetoothSocket.connect();
                    }
                    Toast.makeText(getApplicationContext(), "CONNECTION SUCCESSFUL!", Toast.LENGTH_SHORT).show();
                } catch (Exception e) {
                    Toast.makeText(getApplicationContext(), "Error in connecting", Toast.LENGTH_SHORT).show();
                }
                btListView.setVisibility(View.GONE);
                listView.setVisibility(View.VISIBLE);

                try {
                    outputStream = bluetoothSocket.getOutputStream();
                    inputStream = bluetoothSocket.getInputStream();
                    Toast.makeText(getApplicationContext(), "Streams retrieved", Toast.LENGTH_SHORT).show();
                    //listenForData();
                } catch (Exception e) {
                    Toast.makeText(getApplicationContext(), "Error in getting streams", Toast.LENGTH_SHORT).show();
                }



                final Handler handler = new Handler();
                try {
                    BluetoothSocketListener bluetoothSocketListener = new BluetoothSocketListener(bluetoothSocket, handler, getApplicationContext());
                    Thread newThread = new Thread(bluetoothSocketListener);
                    newThread.start();
                    Toast.makeText(getApplicationContext(), "New Thread Running", Toast.LENGTH_SHORT).show();
                }catch(Exception e){
                    Toast.makeText(getApplicationContext(), "Error in new thread", Toast.LENGTH_SHORT).show();
                }

            }
        });
    }catch (Exception e){
        Toast.makeText(getApplicationContext(), "Error in 2nd listview", Toast.LENGTH_SHORT).show();
    }

此代码块末尾的Handler创建另一个Thread,它继续运行以接收其他设备发送的数据。这是该线程的代码:

public class BluetoothSocketListener implements Runnable {

private BluetoothSocket bluetoothSocket;
private Handler handler;
Context context;
public BluetoothSocketListener(BluetoothSocket socket, Handler handler, Context c){
    this.bluetoothSocket=socket;
    this.handler=handler;
    this.context=c;
}

@Override
public void run(){
    int bufferSize=1024;
    final byte[] buffer=new byte[bufferSize];
    try {
        final InputStream inputStream = bluetoothSocket.getInputStream();
        int bytesRead = -1;
        String message = "";
        handler.post(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(context, "Listening for data with Stream: "+inputStream.toString(), Toast.LENGTH_SHORT).show();
            }
        });
        while (true){
            bytesRead= inputStream.read(buffer);
            final String str=new String(buffer);
            try{
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(context, str, Toast.LENGTH_SHORT).show();
                    }
                });
            }catch (Exception e){
                Toast.makeText(context, "Error in reading characters", Toast.LENGTH_SHORT).show();
            }
        }

    }catch(Exception e){
        handler.post(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(context, "Error in listening to data", Toast.LENGTH_SHORT).show();
            }
        });
    }
}}

并且,在MainActivity类中具有此功能的任何设备上的数据都被写入OutputStream:

public void sendData(String s) throws IOException{
    byte[] byteString=s.getBytes();
    outputStream.write(byteString);
    outputStream.flush();
    Toast.makeText(getApplicationContext(), "Message sent", Toast.LENGTH_SHORT).show();
}

String s是需要发送的字符串。

在两台独立设备上同时运行我的应用程序(一台设备安装了Android 5.1.1,另一台设备安装了Android 6.0),这些设备在两部手机上的配对设备列表中以及相互之间的连接方式如何。

显示所有的祝酒词,包括&#34; New Thread Running&#34;和#34;倾听数据&#34;所以代码运行正常。在尝试发送任何内容时,&#34;消息已发送&#34;吐司也被展示了。 但是数据没有收到(代码没有超过inputStream.read(缓冲区)作为测试Toast,因为它没有显示)。

这意味着它正在进行到那一点并等待从InputSream中读取永远不会出现的数据,即使它已成功写入另一台设备上的OutputStream。

关闭应用程序后,出现错误消息&#34;收听数据时出错&#34;显示证明第二个线程始终正常运行。

任何人都可以告诉我哪里出错了吗?我的设备是从一个插槽查看InputStream,而第二个设备将数据发送到另一个插槽。如果是这样,我怎么能确保它听到正确的套接字?

我查看了StackOverflow上的所有类似问题,甚至已经检查了Google的蓝牙聊天应用程序示例,但无法找到任何解决方案。我尝试了不同的方式发送字符串(使用OutputStreamWriting并将其编码为UTF-8等)并接收它(尝试逐个字符地接收数据,或者在InputStream上使用BufferedReader),但每次都有完全相同的问题。 该应用程序的其余部分工作正常。

感谢。

1 个答案:

答案 0 :(得分:0)

我为第一篇文章道歉。这是一个答案,如果我正确理解蓝牙你的run()函数在 CONNECTING 阶段和 CONNECTED 之前启动。 read函数从不完整的连接开始。

@Override
public void run(){
    int bufferSize=1024;
    final byte[] buffer=new byte[bufferSize];
    try {
        final InputStream inputStream = bluetoothSocket.getInputStream();
        int bytesRead = -1;
        String message = "";
        handler.post(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(context, "Listening for data with Stream: "+inputStream.toString(), Toast.LENGTH_SHORT).show();
            }
        });
        while (true){
            bytesRead= inputStream.read(buffer);
            final String str=new String(buffer);

具体来说,解决您对聊天示例的引用以及您编辑某些代码的相似之处。问题部分是由于你使用了Toast&#34;而不是Log.d API因为图形需要很长时间。

// Constants that indicate the current connection state
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

/** Constructor. Prepares a new BluetoothChat session.
 *
 * @param context The UI Activity Context
 * @param handler A Handler to send messages back to the UI Activity
 */
public BluetoothSPP(Context context, Handler handler) {
    mAdapter = BluetoothAdapter.getDefaultAdapter();
    mState = STATE_NONE;
    mHandler = handler;
}

/** Set the current state of the chat connection
 *
 * @param state An integer defining the current connection state
 */
private synchronized void setState(int state) {
    Log.v(TAG, "BT State changed " + mState + " -> " + state);
    mState = state;

    // Give the new state to the Handler so the UI Activity can update
    mHandler.obtainMessage(Constants.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
}

观察mConnectedThread.start()和setState(STATE_CONNECTED)之间的消息处理程序

public synchronized void connected(BluetoothSocket socket, BluetoothDevice
        device, final String socketType) {
    Log.d(TAG, "BT connected, Socket Type:" + socketType);

    // Cancel the thread that completed the connection
    if (mConnectThread != null) {
        mConnectThread.cancel();
        mConnectThread = null;
    }

    // Cancel any thread currently running a connection
    if (mConnectedThread != null) {
        mConnectedThread.cancel();
        mConnectedThread = null;
    }

    // Cancel the accept thread because we only want to connect to one device
    if (mSecureAcceptThread != null) {
        mSecureAcceptThread.cancel();
        mSecureAcceptThread = null;
    }
    if (mInsecureAcceptThread != null) {
        mInsecureAcceptThread.cancel();
        mInsecureAcceptThread = null;
    }

    // Start the thread to manage the connection and perform transmissions
    mConnectedThread = new ConnectedThread(socket, socketType);
    mConnectedThread.start();

    // Send the name of the connected device back to the UI Activity
    Message msg = mHandler.obtainMessage(Constants.MESSAGE_DEVICE_NAME);
    Bundle bundle = new Bundle();
    bundle.putString(Constants.DEVICE_NAME, device.getName());
    msg.setData(bundle);
    mHandler.sendMessage(msg);

    setState(STATE_CONNECTED);
}

这是读线程。

private class ConnectedThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final InputStream mmInStream;
    private final OutputStream mmOutStream;

    public ConnectedThread(BluetoothSocket socket, String socketType) {
        Log.v(TAG, "BT Connected: " + socketType);
        mmSocket = socket;
        InputStream tmpIn = null;
        OutputStream tmpOut = null;

        // Get the BluetoothSocket input and output streams
        try {
            tmpIn = socket.getInputStream();
            tmpOut = socket.getOutputStream();
        } catch (IOException e) {
            Log.e(TAG, "BT sockets not created", e);
        }

        mmInStream = tmpIn;
        mmOutStream = tmpOut;
    }

    public void run() {
        Log.i(TAG, "BEGIN BT Monitor");
        byte[] buffer = new byte[1024];
        int bytes;

        // Keep listening to the InputStream while connected
        while (mState == STATE_CONNECTED) {
            try {
                // Read from the InputStream
                bytes = mmInStream.read(buffer);

                // Send the obtained bytes to the UI Activity
                mHandler.obtainMessage(Constants.MESSAGE_READ, bytes, -1, buffer)
                        .sendToTarget();
            } catch (IOException e) {
                Log.e(TAG, "BT Monitor Disconnected", e);
                connectionLost();
                // Start the service over to restart listening mode
                BluetoothSPP.this.start();
                break;
            }
        }
        Log.i(TAG, "End BT Monitor");

    }

Android Studio logcat中的输出如下所示。它从未进入while(mState == STATE_CONNECTED)循环。

Output of Android Studio logcat during code execution

我通过添加处理连接状态的循环来纠正代码。

public void run() {
        Log.i(TAG, "BEGIN BT Monitor");
        byte[] buffer = new byte[1024];
        int bytes;

        while (mState == STATE_CONNECTING){
            Log.i(TAG, "BT Monitor Paused");
        }
        // Keep listening to the InputStream while connected
        while (mState == STATE_CONNECTED) {
            try {
                // Read from the InputStream
                bytes = mmInStream.read(buffer);

                // Send the obtained bytes to the UI Activity
                mHandler.obtainMessage(Constants.MESSAGE_READ, bytes, -1, buffer)
                        .sendToTarget();
            } catch (IOException e) {
                Log.e(TAG, "BT Monitor Disconnected", e);
                connectionLost();
                // Start the service over to restart listening mode
                BluetoothSPP.this.start();
                break;
            }
        }
        Log.i(TAG, "End BT Monitor");

    }

logcat输出显示&#34; STATE_CONNECTING&#34;在说明连接已完成的日志消息之前发生了15次循环,并且在代码执行之后发生了一次(显示时间依赖性)Toast和其他消息。

Android Studio logcat output showing code execution