简体   繁体   中英

Android - Pass object via bluetooth

The Bluetooth chat example for Android is very useful to learn how to pass strings between phones - is it possible to use the same code to pass objects between phones? I have the same classes defined in both phones, I just want to pass the instance of one class from one phone to another. Is there any sample code available? I tried using serialization and replacing outputstream and inputstream in the chat example with objectoutputstream and objectinputstream but it didn't seem to work

The best way I found to handle this was the following:

  1. I set up my objects as implementing Serializable that I wanted to send.
  2. I set up the following code to manage the messages:

     public byte[] serialize() throws IOException { ByteArrayOutputStream b = new ByteArrayOutputStream(); ObjectOutputStream o = new ObjectOutputStream(b); o.writeObject(this); return b.toByteArray(); } //AbstractMessage was actually the message type I used, but feel free to choose your own type public static AbstractMessage deserialize(byte[] bytes) throws IOException, ClassNotFoundException { ByteArrayInputStream b = new ByteArrayInputStream(bytes); ObjectInputStream o = new ObjectInputStream(b); return (AbstractMessage) o.readObject();
  3. I changed the write statements to accept a Serializable, and then make the final write:

     /** * Write to the connected OutStream. * @param buffer The bytes to write */ public void write(AbstractMessage buffer) { try { Log.v(TAG,"Writing \""+(buffer.serialize())+"\""); mmOutStream.write(buffer.serialize()); // Share the sent message back to the UI Activity mHandler.obtainMessage(AbstractMessageManager.MESSAGE_WRITE, -1, -1, buffer).sendToTarget(); } catch (IOException e) { Log.e(TAG, "Exception during write", e); } }

The Bluetooth Chat example is a demonstration of using the Serial Port Profile (SPP) which is based upon RFCOMM. You can serially send across any data you like once the connection is established; you simply need to be able to represent your objects into a serial stream of bytes, ie serialize them.

Therefore the use of serialization would certainly be a way of getting your objects sent over the link. The Bluetooth API's send and receive functions deal with arrays of bytes, but you could easily adapt the Bluetooth Chat example to use streams, eg the send function would read bytes out of a stream and put them into an array buffer, then you send that buffer, etc. Then the application code would simply talk via input and output stream pipes - that's one way I've done it in the past.

So there's nothing wrong with your actual idea. The bigger problem is that the way you've implemented it is not right, and more problematic still is that the way you've asked your question is quite poor, too. You need to be more descriptive about exactly what didn't work, explain what debugging you've already tried, and post code samples and Logcat outputs so we can help you properly.

Finally, I did find what I think is a bug in the Bluetooth Chat code example: The data receive function passes a reference of the receive byte array to the ArrayList that's used to show each line of text received. This is alright when small amounts of slow text are being transmitted across, but when you try to send large amounts of data, you start to see the data being corrupted, presumably because the ArrayList adapter is still reading bytes out of that same array when the array is being filled with even newer data.

Facing same problem... When i am sending a series of objects from one Android device, data sends properly... But in receiving end all objects does not construct from received byte[].

Error occurs randomly for any received object but the same code works properly in Java... I think the some bytes misses when transferring data from one device to another...

Serializable object to byte[] and byte[] to object conversion can be done with the following code

public static byte[] toByteArray(Object obj)
{
    byte[] bytes = null;
    ObjectOutputStream oos = null;

    try 
    {
        oos = new ObjectOutputStream(new ByteArrayOutputStream());
        oos.writeObject(obj);
        oos.flush();

        return bos.toByteArray();
    }
    catch(Exception e)
    {
        Log.e("Bluetooth", "Cast exception at sending end ...");
    }

    return bytes;
}

public static Object toObject(byte[] bytes) 
{
    Object obj = null;
    ObjectInputStream ois = null;

    try 
    {
        ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
        return ois.readObject();
    } 
    catch(Exception ex)
    {
        Log.e("Bluetooth", "Cast exception at receiving end ...");
    }

    return obj;
}

Trev16v, First of all, thanks for your initial feedback.

In order to serialise my object, I used the classes serializeObject and deserializeObject from http://www.jondev.net/articles/Android_Serialization_Example_(Java ) They seem to work well: if I serialise an object (created out of a class that implements Serializable) from a phone/activity and deserialize it from the same phone i manage to get an object out of the generated byte[].

I then tried to use the same code in the class BluetoothChatServices in the bluetooth chat example in oder to send the serialised object to the other phone (in that example there is

    public ConnectedThread(BluetoothSocket socket) {
        Log.d(TAG, "create ConnectedThread");
        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, "temp sockets not created", e);
        }

        mmInStream = tmpIn;
        mmOutStream = tmpOut;
    }

and the bytes are passed using

public void write(byte[] buffer) {
        try {
            mmOutStream.write(buffer);

            // Share the sent message back to the UI Activity
            mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer)
                    .sendToTarget();
        } catch (IOException e) {
            Log.e(TAG, "Exception during write", e);
        }
    }

and read using

   public void run() {
        Log.i(TAG, "BEGIN mConnectedThread");
        byte[] buffer = new byte[10240];
        int bytes;
        // Keep listening to the InputStream while connected
        while (true) {
            try {
                // Read from the InputStream
                bytes = mmInStream.read(buffer);

                    // Send the obtained bytes to the UI Activity
                mHandler.obtainMessage(BluetoothManageActivity.MESSAGE_READ, bytes, -1, buffer)
                        .sendToTarget();
            } catch (IOException e) {
                Log.e(TAG, "disconnected", e);
                connectionLost();
                break;
            }
        }
    }

The problem with using BluetoothChatServices as it is is that the array of bytes received on the other phone is different from the one sent when it comes to serialised objects. For example, to give an idea element [0] of the seriealized object is =-84 when i send it, the one i receive from the other phone has element [0] to [4] =0, then [5]=4 and all the other elements are also not aligned. I tried in the methods write and run above to change Inputstream and Outputstream with ObjectInputStream and ObjectOutputstream but without success (if this was supposed to be the way to implement it, I can post the code I tried to use)

Again, thanks a lot for your help, I am new to all these concepts so if I am talking nonsense I will be also happy to be addressed to a tutorial

thanks

The answer is yes. A String is an Object. Remember? But how exactly to do it, I am still searching for a solution and that's what brought me here...

I actually found the problem - when the bytes are loaded using

try {
   // Read from the InputStream
    bytes = mmInStream.read(buffer);

they are actually loaded in 2 steps.. While debugging and stepping into the code I found that if first loads 990 bytes and then the remaining bytes.. so when i am back to the UI handler i see only the bytes loaded in the second step..

i wonder if there is a way to force to load all bytes at once

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