Why InputStream.inAvailable() is always returning 0? - android

I am making an android app and sending an xml to an ip address. I should get back an xml as response but bytes in inputstream buffer is always empty. I am using following code:
String sMessage = "<Server><CONNECT><IP>192.168.1.14</IP><Client_ID>123</CLIENT_GUID></CONNECT></Server>";
Socket clientSocket = null;
clientSocket = new Socket("192.168.252.148",34543);
PrintWriter pw = new PrintWriter(clientSocket.getOutputStream(),true);
pw.write(sMessage);
InputStream in = clientSocket.getInputStream();
byte[] buffer = new byte[in.available()];
System.out.println("buffer size: "+buffer.length);
pw.close();
in.close();
clientSocket.close();
Any idea why am i not getting bytes in my inputstream. Thanks in advance.

http://docs.oracle.com/javase/6/docs/api/java/io/InputStream.html#available()
The available method for class InputStream always returns 0.
This method should be overridden by subclasses.
Try wrapping using a BufferedInputStream.
BufferedInputStream in = new BufferedInputStream(clientSocket.getInputStream());

I should get back an xml as response but bytes in input stream buffer
Maybe so, but not instantaneously, which is what your code assumes. There are few if any correct uses of available(), and this isn't one of them. Just block in the read.

.available() can not be used in inter-process communication (serial included), since it only checks if there is data available (in input buffers) in current process.
In serial communication, when you send a massage and then immediately call available() you will mostly get 0 as serial port did not yet reply with any data.
The solution is to use blocking read() in a separate thread (with interrupt() to end it):
try this Thread interrupt not ending blocking call on input stream read
on some streams (such as BufferedInputStream, that have an internal buffer), some bytes are read and kept in memory, so you can read them without blocking the program flow. In this case, the available() method tells you how many bytes are kept in the buffer.
new BufferedOutputStream(clientSocket.getOutputStream()));
new BufferedInputStream (clientSocket.getInputStream())

Related

Transfer database data from one android device to another

I have an app that needs to implement a 'share' option to transfer data contained in the device's local database to another device, where that device can take this data and insert it into the appropriate tables in the device's database.
I have communication working over bluetooth, I'm just looking for a good way to transfer this data across. Is there an easy way to do an sqlite dump on device A, transfer this across to device B using bluetooth, and have device B reinsert this data?
Implementing aContentProvider is how you leverage the Android framework to do CRUD operations on a database.
A good way could be to transform a row into Json and unpackage that string on the receiving side to insert it. This way is more testable, easier to recover from errors during send, but might be very slow depending on the size of your data. For speeding it up I would send multiple rows in batches and test to see what batch size would be best for speed and reliability.
A fast way might be to dump the data to flat file then use the FileProvider to provide access to that file as a URI and try something like the following from here
public void sendFile(Uri uri, BluetoothSocket bs) throws IOException {
BufferedInputStream bis = new BufferedInputStream(getContentResolver().openInputStream(uri));
OutputStream os = bs.getOutputStream();
try {
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
// we need to know how may bytes were read to write them to the byteBuffer
int len = 0;
while ((len = bis.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
} finally {
bis.close();
os.flush();
os.close();
bs.close();
}
}

Android Inputread stream reads exactly the given buffer size?

I am reading a file with:
char [] buffer = new char[300];
FileInputStream istream = new FileInputStream(path);
InputStreamReader file = new InputStreamReader(istream);
size = file.read(buffer);
file.close();
After a few tries, it turns out that the file.read(buffer) reads exactly the number of chars allocated for buffer (in this case, 300, even that the file has much more characers in it).
Can I rely on read() always reading as much as it can, without generating any exception?
Or is this an undocumented feature?
The read method description says:
Reads characters from this reader and stores them in the character
array buf starting at offset 0. Returns the number of characters
actually read or -1 if the end of the reader has been reached.
There is no mention of the buffer allocation issue.
This is very important, and a good thing that it works this way, because it allows you to define the size of the buffer as you want/need and there is no need to guess, no need to code for exceptions. Actually, it is read(char[] buffer) but it works as read(char[] buffer, int size).
Yes you can rely on this call, unless an I/O error occurs, which is already mentionned in the api.
If you look at the code of read(char cbuf[]) you'll notice it calls the method public int read (char[] buffer, int offset, int length).
From Android source code:
public int read(char cbuf[]) throws IOException { read(cbuf, 0, cbuf.length);}
In your implementation, you need to continue reading the file with file.read(buffer) to obtain remaining bytes. The content of buffer needs to be appended to another buffer that will grow, depending on the size of the file you're reading.
You could also allocate that buffer with the size of the file with the method getTotalSpace()

When some conditions triggers, have to do automatic file transfer over bluetooth using Android Bluetooth API?

In my application i want send a file or text over Bluetooth to another Bluetooth device(receiver device may be android,Nokia,LG,etc..). I want to send a file whenever the sever returns the data. For example am checking weather if the climate level falls below any particular given value. It automatically, need to send data over Bluetooth to the receiver device. It wont allow the user to send.
How can I implement it using android Bluetooth API?
And also I need to transfer any file via Bluetooth by converting it to byte array. I have gone through Bluetooth chat example. In that they have given the buffer size of 1024. If the file size more than 1024 byte means how should I transfer. Whether I have to sent each 1024 byte every time and have to merge it at the receiver side or else any other better way is available?
Thanks in advance.
As far as I understand you're asking three questions.
How to send a file whenever a server returns data: You basically open a connection to the server (e.g. http, but might also be any other TCP or UDP-based protocol). Then you listen for incoming data; once you receive data, you trigger whatever action you want. These are some relevant calls for a starting point when your server is not using http (untested, consult the docs for details and alternatives):
Socket s = new Socket('your.server.com', 47000);
s.connect();
SocketChannel c = s.getChannel();
ByteBuffer buffer = new ByteBuffer(1);
c.read(buffer); // blocks until bytes are available
How to initiate a Bluetooth connection automatically: Obtain the target device's BluetoothDevice object, then connect to it - as in the BluetoothChat demo.
How to send a file / more than 1024 bytes via Bluetooth: Yes you have to split your data into blocks on the sending side and reassemble them on the receiving side (mind to send the filesize before the actual data, so the receiver knows when the file is complete). You can also use reasonably larger byte buffers. I'd recommand using a maximum block size of 64 Kb: This allows you to resend blocks without too much (time) cost and doesn't consume too much memory.
As a starter regarding 3., something like this could the core of the sending side (untested and without error handling, just to give the idea):
// Send the file size
OutputStream out = socket.getOutputStream();
ByteBuffer header = ByteBuffer.allocate(8);
header.putLong(file.length();
out.write(header.array());
// Send the file in chunks
byte buffer[1024];
InputStream in = new BufferedInputStream(new FileInputStream(file));
int length = in.read(buffer);
while (length > 0) {
out.write(buffer, 0, length);
if (length < 1024) break;
length = in.read(buffer, 0, sizeof(buffer));
};
... and the receiving side:
// Receive and unmarshal the file size
InputStream in = socket.getInputStream();
ByteBuffer header = ByteBuffer.allocate(8);
byte buffer[1024];
in.read(buffer, 0, 8);
header.put(buffer);
long filesize = header.getLong();
long receivedBytes = 0;
// Receive the file
OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
int length = in.read(buffer);
while ((receivedBytes < filesize) && (length > 0)){
out.write(buffer, 0, length);
receivedBytes += length;
length = in.read(buffer);
}
if (receivedBytes != filesize) ... // Assure the transfer was successful

BufferedInputStream.read() not reliably returning data to my app - data bunches up

My app receives data through a serial port... they're typically small chunks of data. For example, sometimes it 40 bytes, sometimes 60 bytes. All the chunks of data are separated by a second, or possibly even a minute.
I read that using BufferedInputStream is good for reading chunks of data so that the app doesn't create a lot of CPU overhead by reading data byte by byte.
So that's what I did - just like this example: http://www.roseindia.net/java/example/java/io/ReadFilterFile.shtml
When it works, it works great!
My app gets a complete chunk of data - I was worried that I would receive incomplete chunks, but no, to my amazement it's complete chunks.
However, sometimes it doesn't work so well
What seems to happen is that a small chunk of data doesn't cause the read() method to complete. When a little bit larger chunk comes along later then finally the read() will return. This is undesirable !
I do not want my app to be denied a chunk of data until another chunk arrives.
Question:
How do I ensure that BufferedInputStream.read() returns shortly after a small chunk of data was received ? Is byte-by-byte read the only way ?
I have it solved - the solution was to use smaller buffers... taking the roseindia.net sample, the following fixes the read() to always return after a chunk of data:
final int BUFFER_SIZE = 128;
byBuffer = new byte[BUFFER_SIZE];
try
{
FileInputStream fin = new FileInputStream("Filterfile.txt");
BufferedInputStream bis = new BufferedInputStream(fin, BUFFER_SIZE*2);
// Now read the buffered stream.
while (bis.available() > 0)
{
int iBytesRead = bis.read(byBuffer, 0, BUFFER_SIZE);
}
}
catch (Exception e)
{
System.err.println("Error reading file: " + e);
}
maybe the 8K default buffer was too large and the small chunks of data didn't reliably pass some threshold ?

Problem with audio

In my android app I can record audio and save it on the phone/sdk. I checked that it is audible and clear when i play it back on the phone. The size of the audio file it created is 5.9kb(.amr format).
Next i upload the file to the server, it stores the audio on sql db. The upload is successful. When the uploaded audio is played, it is all garbled...
In the database i store the audio in a column with datatype image and is of length 16.
My question is ..why is the noise garbled after upload. How do i verify that the audio is saved correctly without any noise added.
Code for file upload
InputStream = new DataInputStream(new FileInputStream( FileName));
byte[] responseData = new byte[10000];
int length = 0;
StringBuffer rawResponse = new StringBuffer();
while (-1 != (length = InputStream.read(responseData)))
rawResponse.append(new String(responseData, 0, length));
String finalstring = rawResponse.toString();
voicedataArray = finalstring.getBytes();
Your problem is very much likely due to the use of StringBuffer to buffer the response. A character in Java is a two-byte entity corresponding to a Unicode character point. The documentation for String#getBytes() says:
Returns a new byte array containing the characters of this string
encoded using the system's default charset.
So there's no guarantee that the bytes you are passing in, being converted to characters, then back to bytes is the same stream you passed in the first place.
I think you would need to code your solution using a dynamically expanding byte buffer in place of the StringBuffer.
Also, two notes about the usage of StringBuffer:
1) All accesses to the StringBuffer are synchronized, so you're paying a performance penalty. StringBuilder is a modern-day replacement that doesn't do synchronization under the hood.
2) Each time you append to the StringBuffer:
rawResponse.append(new String(responseData, 0, length));
you are allocating a new string and throwing it away. That's really abusive to the garbage collector. StringBuffer actually has a form of append() that will directly take a char array, so there is no need to use an intermediate String. (But you probably don't want to use a StringBuffer in the first place).

Categories

Resources