简体   繁体   中英

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.

UPDATE: I've tried something new, with help from SeahawksRdaBest and am now getting new errors, so here is new code and logs:

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:

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###

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 . 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. Obviously you can't do that. Remember you have to pass a Bluetooth device object to the 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(),

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. 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. Ill let you figure out how to confirm that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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