简体   繁体   English

InputStream不通过蓝牙接收数据

[英]InputStream not receiving data via Bluetooth

EDIT 1: MCVE- 编辑1:MCVE-

I let my entire code be in the main question, but since I was asked for an MCVE- 我让我的整个代码成为主要问题,但是由于要求我提供MCVE,

The device is not receiving the data sent to it by the other connected Android device. 该设备未收到其他已连接的Android设备发送给它的数据。 Code is not running past "inputStream.read(buffer)" as it is getting no data to receive. 代码没有经过“ inputStream.read(buffer)”,因为它没有数据要接收。

The code for sending data: 发送数据的代码:

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();
}

For receiving: 接收:

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();
            }
        }

Also, I have connected my socket this way: 另外,我以这种方式连接了我的插座:

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

Using Port Number 1 or the createRfCcommSocketToServiceRecord was not working as the connection was failing then. 由于连接失败,因此无法使用端口号1或createRfCcommSocketToServiceRecord。

THE ENTIRE PROBLEM: 整个问题:

I am working on an app where I need a feature to provide a 2 way communication between two android devices via Bluetooth. 我正在开发一个需要通过蓝牙在两个android设备之间提供双向通信功能的应用程序。 The data being sent will be simple strings. 发送的数据将是简单的字符串。

I am able to connect two devices properly. 我能够正确连接两个设备。 Here is my code for that: 这是我的代码:

 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));

This displays all paired devices on a ListView. 这会在ListView上显示所有已配对的设备。 Now upon selecting any of those devices, a connection is made with the following: 现在选择这些设备中的任何一个,就可以与以下设备建立连接:

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();
    }

The Handler at the end of this block of code creates another Thread which keeps running to receive the data sent by the other device. 此代码块末尾的处理程序创建另一个线程,该线程一直运行以接收另一设备发送的数据。 Here is the code for that 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();
            }
        });
    }
}}

And, the data is being written to the OutputStream on any device with this function in the MainActivity class: 并且,使用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();
}

The String s is the string that is needed to be sent. String s是需要发送的字符串。

Upon running my app on two separate device simultaneously (One device has Android 5.1.1 and the other has Android 6.0), the devices how up in the list of paired devices on both phones and the connections to each other is made. 在两台单独的设备上同时运行我的应用程序(一台设备具有Android 5.1.1,另一台设备具有Android 6.0)时,这些设备在两部手机的已配对设备列表中以及彼此之间的连接情况如何。

All the toasts are displayed, including the "New Thread Running" and "Listening For Data" so the code does run fine. 显示所有敬酒,包括“正在运行新线程”和“侦听数据”,因此代码确实运行良好。 Upon trying to send anything, the "Message sent" toast is getting displayed too. 尝试发送任何内容时,也会显示“已发送消息”吐司。 But the data is not getting received (Code isn't running past inputStream.read(buffer) as a test Toast I had put after it didn't get displayed). 但是数据没有被接收到(代码没有运行过inputStream.read(buffer),作为我在未显示它之后进行的测试Toast)。

This means that it is going upto that point and waiting to read the data from InputSream that never comes, even if it is successfully written to the OutputStream on the other device. 这意味着它已经到了这一点,并等待从InputSream读取永远不会出现的数据,即使该数据已成功写入其他设备上的OutputStream中也是如此。

Upon closing the app, the error message "Error in listening to data" is displayed proving that the 2nd Thread was running fine continuously throughout. 关闭应用程序后,将显示错误消息“在侦听数据时出错”,证明第二个线程一直在正常运行。

Can anyone please tell where I have gone wrong? 谁能告诉我我哪里出问题了? Is it that my device is looking into an InputStream from one socket while the data is being sent to a different one by the 2nd device. 是我的设备正在从一个套接字查看InputStream时,第二个设备正在将数据发送到另一个套接字。 If so, how am I supposed to make sure it listens at the right socket? 如果是这样,我应该如何确保它在正确的套接字上侦听?

I looked through all similar questions on StackOverflow and have even checked the Bluetooth Chat App example by Google but couldn't find any solution to this.I have tried different ways of sending the string (using OutputStreamWriting and encoding it in UTF-8, etc) and receiving it (trying to receive data character by character, or using BufferedReader on the InputStream), but there was the exact same problem every time. 我在StackOverflow上浏览了所有类似的问题,甚至检查了Google的Bluetooth Chat App示例,但找不到任何解决方案。我尝试了不同的发送字符串的方法(使用OutputStreamWriting并将其编码为UTF-8等) )并接收它(尝试逐个字符地接收数据,或在InputStream上使用BufferedReader),但是每次都存在完全相同的问题。 The rest of the app works fine. 该应用程序的其余部分工作正常。

Thanks. 谢谢。

I apologize for the first post. 我对第一篇文章表示歉意。 This is an answer, if I understand Bluetooth correctly your run() function starts during the CONNECTING phase and before CONNECTED . 这是一个答案,如果我正确理解蓝牙,则run()函数在CONNECTING阶段和CONNECTED之前启动。 The read function is starting on an incomplete connection. 读取功能从不完整的连接开始。

@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);

Specifically, addressing your reference to the Chat example and the similarities that you edited some of that code. 具体来说,解决您对“聊天”示例的引用以及您编辑该代码的相似之处。 The problem is partly due to your use of "Toast" instead of the Log.d API because it takes so long for graphics. 问题的部分原因是您使用“ Toast”而不是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();
}

Observe the message handler between mConnectedThread.start() and setState(STATE_CONNECTED) 观察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);
}

Here is the read thread. 这是读取线程。

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");

    }

The output in the Android Studio logcat looked like this. Android Studio logcat中的输出如下所示。 It never entered the while (mState == STATE_CONNECTED) loop. 它从未进入while(mState == STATE_CONNECTED)循环。

Output of Android Studio logcat during code execution 代码执行期间Android Studio logcat的输出

I corrected the code by adding a loop that handled the connecting state. 我通过添加处理连接状态的循环来更正代码。

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");

    }

The logcat output shows the "STATE_CONNECTING" loop occurring 15 times before the Log message stating the connection had been completed and once after (showing the time dependency) of Toast and other messages on code execution. logcat输出显示“ STATE_CONNECTING”循环发生在Log消息表明连接已完成之前15次,而Toast和其他消息在代码执行之后发生一次(显示时间依赖性)。

Android Studio logcat output showing code execution Android Studio logcat输出显示代码执行

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM