简体   繁体   English

两个设备之间的蓝牙数据传输不起作用

[英]Bluetooth data transfer between two devices not working

I'm trying to make bluetooth connection between two devices but so far I haven't been able to make it work. 我正在尝试在两个设备之间建立蓝牙连接,但到目前为止,我还无法使其工作。
ATM I have one app on two phones, and depending on bluetooth address one should send information and the other should receive it. 自动取款机我在两部手机上有一个应用程序,根据蓝牙地址,一个应发送信息,而另一个应接收信息。

I want it to work like this: open app on receiver phone that will wait and listen until something happens, then open app on transmitter phone which will connect to receiver and transmit the message. 我希望它像这样工作:在接收器手机上打开应用程序,它将等待并监听直到发生某些事情,然后在发送器手机上打开应用程序,该应用程序将连接到接收器并发送消息。

NOTICE: The app is currently running on Android 5 on one phone and 4.3 on the other. 注意:该应用程序当前在一部手机上运行Android 5,在另一部手机上运行4.3。

UPDATE: I've tried something new, with help from SeahawksRdaBest and am now getting new errors, so here is new code and logs: 更新:在SeahawksRdaBest的帮助下,我尝试了一些新的东西,现在遇到了新的错误,因此这里是新的代码和日志:

package com.example.xxxxx;


import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.UUID;

import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;


@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
public class BluetoothClass extends Fragment{
    BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    BluetoothDevice selectedDevice;

    protected static final int SUCCESS_CONNECT = 0;
    protected static final int MESSAGE_READ = 1;

    final int STATE_CONNECTED = 2;
    final int STATE_CONNECTING = 1;
    final int STATE_DISCONNECTED = 0;

    private final UUID MY_UUID = UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66");
    public byte[] completeData;
    double totalDistance = 0;
    int wheelRotations=0;

    private static final String address = "00:EE:BD:D1:66:45"; // Phone 1
    private static final String address2 = "18:E2:C2:31:08:AC"; // Phone 2
    private static final String TAG = "BTLOG";

    Handler mHandler = new Handler(){           
        public void handleMessage(Message msg){
            super.handleMessage(msg);
            switch(msg.what){
                case SUCCESS_CONNECT:
                    Log.i(TAG, "CONNECTED");
                    break;

                case MESSAGE_READ:
                    byte[] readBuf = (byte[])msg.obj;
                    Log.v(TAG, "READING: "+readBuf.toString());
            }
        }       
    };

    public void onCreate(Bundle savedInstance){
        super.onCreate(savedInstance);
    }

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
        View rootview = inflater.inflate(R.layout.bluetooth, container,false);      

        rootview.findViewById(R.id.connectDevice).setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                BluetoothDevice selectedDevice = null;

                // If hardcoded device 1, then connect to device 2, or other way around
                if (mBluetoothAdapter.getAddress().equals(address)) {
                    selectedDevice = selectedDevice(address2);
                }
                else if (mBluetoothAdapter.getAddress().equals(address2)) {
                    selectedDevice = selectedDevice(address);
                }
                mBluetoothAdapter.cancelDiscovery();
                ConnectThread ct = new ConnectThread(selectedDevice);
                ct.start();
            }
        });     
        return rootview;
    }   

    public void onActivityCreared(Bundle savedInstanceState){
        super.onActivityCreated(savedInstanceState);
    }

    public void onStart(){
        super.onStart();
    }       

    public void onResume(){
        super.onStart();    
    }

    public void onStop(){
        super.onStart();
    }

    // Get bluetooth device from known address
    public BluetoothDevice selectedDevice(String deviceAddress){
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        BluetoothDevice device;     
        device = mBluetoothAdapter.getRemoteDevice(deviceAddress);
        return device;
    }

    public class ConnectThread extends Thread {
        private final BluetoothSocket mmSocket;
        private BluetoothSocket tmp;
        private final BluetoothDevice mmDevice;

        public ConnectThread(BluetoothDevice device) {
            mmDevice = device;

            try {
                tmp = mmDevice.createRfcommSocketToServiceRecord(MY_UUID);
            } catch (IOException e) {
                Log.e(TAG, "Failed to create temporary socket");
                e.printStackTrace();
            }

            mmSocket = tmp;
            Log.i(TAG, "Finished creating socket");
        }

        public void run() {
            mBluetoothAdapter.cancelDiscovery();

            Log.i(TAG, "Connecting through socket");
            try {
                mmSocket.connect();
            } catch (IOException connectException) {
                Log.e(TAG, "Connection through socket failed: "+connectException);
                Log.i(TAG, "Trying fallback method");

                try {
                    // fallback method for android >= 4.2
                    tmp = (BluetoothSocket) mmDevice.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(mmDevice,1);
                } catch (IllegalAccessException e) {
                    Log.e(TAG, "Failed to create fallback Illegal Access: "+e);
                    return;
                } catch (IllegalArgumentException e) {
                    Log.e(TAG, "Failed to create fallback Illegal Argument: "+e);
                    return;
                } catch (InvocationTargetException e) {
                    Log.e(TAG, "Failed to create fallback Invocation Target"+e);
                    return;
                } catch (NoSuchMethodException e) {
                    Log.e(TAG, "Failed to create fallback No Such Method"+e);
                    return;
                }

                try {
                    // linked to tmp, so basicly a new socket
                    mmSocket.connect();
                } catch (IOException e) {
                    Log.e(TAG, "Failed to connect with fallback socket: "+e);
                    return;
                }

                Log.i(TAG, "Succesfully connected with fallback socket");
                mHandler.obtainMessage(SUCCESS_CONNECT, mmSocket).sendToTarget();
                return;
            }
            Log.i(TAG, "Succesfully connected with original socket");
                mHandler.obtainMessage(SUCCESS_CONNECT, mmSocket).sendToTarget();

        }       
    }

}

LogCat logs: LogCat日志:

11-23 14:03:56.281: I/BTLOG(12107): Finished creating socket
11-23 14:03:56.281: I/BTLOG(12107): Connecting through socket
11-23 14:03:56.286: D/BluetoothUtils(12107): isSocketAllowedBySecurityPolicy start : device null
11-23 14:03:56.286: W/BluetoothAdapter(12107): getBluetoothService() called with no BluetoothManagerCallback
11-23 14:03:59.696: E/BTLOG(12107): Connection through socket failed: java.io.IOException: read failed, socket might closed or timeout, read ret: -1
11-23 14:03:59.696: I/BTLOG(12107): Trying fallback method
11-23 14:03:59.701: D/BluetoothUtils(12107): isSocketAllowedBySecurityPolicy start : device null
11-23 14:03:59.701: W/BluetoothAdapter(12107): getBluetoothService() called with no BluetoothManagerCallback
11-23 14:03:59.761: E/BTLOG(12107): Failed to connect with fallback socket: java.io.IOException: read failed, socket might closed or timeout, read ret: -1

Hmm one potential problem is that you haven't used any kind of "handler" for repeated messages. 潜在的问题是您没有对重复的消息使用任何类型的“处理程序”。 You need a handler object to deal with the incoming stream at all times otherwise you will come across your socket closed problem. 您需要一个处理程序对象来始终处理传入的流,否则您将遇到套接字关闭问题。

Here is what I mean: 这是我的意思:

/*
 * Bluetooth Connection Threads
 */

public class ConnectThread extends Thread {
   private final BluetoothSocket mmSocket;
   private final BluetoothDevice mmDevice;
   public ConnectThread(BluetoothDevice device) {

        /*
         *  Use a temporary object that is later assigned to mmSocket,
         *  because mmSocket is final                
         */

        BluetoothSocket tmp = null;

        mmDevice = device;

        // Get a BluetoothSocket to connect with the given BluetoothDevice
        try {
            // MY_UUID is the app's UUID string, also used by the server code
            tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
        } catch (IOException e) { }
        mmSocket = tmp;
    }
        public void run() {
        // Cancel discovery because it will slow down the connection
        mBluetoothAdapter.cancelDiscovery();

        try {
       // Connect the device through the socket. This will block
            // until it succeeds or throws an exception
            mmSocket.connect();
        } catch (IOException connectException) {
            // Unable to connect; close the socket and get out
            try {
                mmSocket.close();
            } catch (IOException closeException) {
                Toast.makeText(getActivity(), "Connecting to device failed!", Toast.LENGTH_LONG).show();
            }
                return;
        }

            // Do work to manage the connection (in a separate thread)
            mHandler.obtainMessage(SUCCESS_CONNECT, mmSocket).sendToTarget();
    }

    /** Will cancel an in-progress connection, and close the socket */
    public void cancel() {
        try {
            mmSocket.close();
           } catch (IOException e) { }
    }

}

What todo once connected?? 连接后该怎么办??

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

    public ConnectedThread(BluetoothSocket socket) {
        mmSocket = socket;
        InputStream tmpIn = null;
        OutputStream tmpOut = null;

        // Get the input and output streams, using temp objects because
        // member streams are final
        try {
            tmpIn = socket.getInputStream();
            tmpOut = socket.getOutputStream();
        } catch (IOException e) { }

        mmInStream = tmpIn;
        mmOutStream = tmpOut;
    }


   public void run() {
    byte[] buffer; // buffer store for the stream
        int bytes; // bytes returned from read()
        // Keep listening to the InputStream until an exception occurs
        while (true) {
            try {
                // Read from the InputStream
            // This is app specific your logic here
            // Pass Handler Looper here 
                mHandler.obtainMessage(MESSAGE_READ, buffer).sendToTarget();
                }
                catch (IOException e) {
                    break;
             }
        }
     }
    /* Call this from the main activity to send data to the remote device */
    public void write(byte[] bytes) {
        try {
            mmOutStream.write(bytes);
        } catch (IOException e) { }
    }
}

The Handler: 处理程序:

/*
 * Bluetooth Handler Method
 */
    ConnectedThread connectedThread;
    Handler mHandler = new Handler(){           
        public void handleMessage(Message msg){
            super.handleMessage(msg);
            switch(msg.what){
                case SUCCESS_CONNECT:
                    // Do Something;
                    Toast.makeText(getActivity(),"CONNECTED",Toast.LENGTH_SHORT).show();
                    /*
                     * For loop for test values
                     */
                    connectedThread = new ConnectedThread((BluetoothSocket)msg.obj);
                    listView.setVisibility(View.GONE);
                    connectedThread.start();
                    break;

                case MESSAGE_READ:
                // What to do with app specific data handling?? 
            }
        }       
    };

Check out my github for a working bluetooth example.###Update### 查看我的github以获取有效的蓝牙示例。### Update ###

Update 更新

Ok so a couple of things, 好了,有几件事,

Firstly I don't think you need to use fragments like I did. 首先,我认为您不需要像我一样使用片段。 I needed multiple activities communicating with each other, your project on the other hand might only need one. 我需要多个活动相互交流,而您的项目可能只需要一个活动。 (You can still use the concept of fragments but make sure your calling activity is working correctly calling the fragment). (您仍然可以使用片段的概念,但是请确保您的调用活动正确地调用了片段)。 Look at my answer here for more info about fragments. 这里查看我的答案以获取有关片段的更多信息。

Now, Do you fully understand how bluetooth communication works? 现在,您完全了解蓝牙通信的工作原理吗? To understand this read about java threads . 要了解这一点,请阅读有关Java 线程的信息 Because thats what the above code is based on. 因为那就是上面的代码所基于的。

So if you read carefully the log it tells you, you are trying to connect to a NULL device. 因此,如果您仔细阅读日志告诉您的日志,则您正在尝试连接NULL设备。 Obviously you can't do that. 显然你不能那样做。 Remember you have to pass a Bluetooth device object to the ConnectThread. 请记住,您必须将蓝牙设备对象传递给ConnectThread。 I believe this is where your problem lies. 我相信这就是您的问题所在。 You are not parsing the address correctly. 您没有正确解析地址。 The best way to pass a correct address is to pair the two phones to each other. 传递正确地址的最佳方法是将两部电话配对。 Once they are paired you can pull the correct formatted address from the phone memory and pass it to the connection manager. 配对后,您可以从电话存储器中提取正确格式的地址,并将其传递给连接管理器。

Try this: 尝试这个:

//Define a Set, which is a unique list (don't forget to initialize it!)
Set<BluetoothDevice> pairedDevices;

In onCreateView(), 在onCreateView()中,

public void onCreateView(..){
  pairedDevices = mBluetoothAdapter.getBondedDevices();
  // Your additional code //
  /*Now you have a set containing the correct address of the paired devices to your phone, 
    I would recommend unpair all devices except the one you are concered with this makes life easier 
    as then you know the first (& only) device in the pairedDevice array is the one you want to                
    connect with.
  */  
  // Now simply pass the Set item to your ConnectThread
  ConnectThread ct = new ConnectThread(pairedDevices[0])
  ct.start();
}

Note 注意

The Selected device method I made was structured to pick up the device address from a ListView. 我进行的“选择设备”方法的结构旨在从ListView中获取设备地址。 I created that method specifically so I could see the device I was trying to connect with. 我专门创建了该方法,以便可以看到尝试连接的设备。 You just can't copy paste the code and expect it to work. 您只是无法复制粘贴代码并期望它能工作。 It would also be a great idea to confirm your pairedDevice set got populated. 确认您的pairedDevice集已填充也是一个好主意。 Ill let you figure out how to confirm that. 麻烦您让您弄清楚如何确认。

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

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