Android getInputStream() does not retrieve all bytes, but only sporadically - android

First, I have a class that extends AsyncTask. Then in the doInBackground() method, I have some code that posts an HTTP post message, and gets a response. This response is read into a string as follows:
DataInputStream dis = new DataInputStream(conn.getInputStream());
byte[] data = new byte[32768];
len = dis.read(data, 0, 32768);
if (len > 0)
{
response = new String(data, 0, len);
}
At this point, response should be 4127 bytes (as confirmed by the server). 1/5th of the time it IS 4127 bytes. 2/5 of the time it's 1205 bytes, and 2/5 of the time it's 3853 bytes. I can close the app, reinstall, and I get the same variation.
The person who manages the server logs everything and can confirm the same data is being sent over and over. But Android isn't getting the full stream. This is wireless, not 3g. When I use the debugger, I can see that the string returned is always identical, just chopped off at a random spot.
Sorry for such a vague (stupid?) question, but I've been looking at this for hours and I can't see what's wrong with it...

The read method documentation says: Reads up to len bytes of data from the contained input stream into an array of bytes. An attempt is made to read as many as len bytes, but a smaller number may be read, possibly zero. The number of bytes actually read is returned as an integer.
Depending on different conditions, sometimes you can read all server-sent data, sometimes there is a short-read. In order to get all data you should keep reading the stream in a loop until len is -1, indicating an EOF.
InputStream in = ...;
byte[] dst = new byte[32768]; /* Assuming total len is < 32768 */
int idx = 0;
do {
int len = in.read(dst, idx, 32768 - idx);
idx += len;
} while (len >= 0 || idx < 32768);

Related

InputStream.read() hangs on reading a file

In my app, i'm sending a file from a client, using sockets. On the other side, another client receive the file using InputStream and then bufferedOutputStream save the file in the system.
I don´t know why, the file isn´t utterly transmited. I think this is because of network overload, anyway, i don´t know how to solve it.
Transmiter is:
Log.d(TAG,"Reading...");
bufferedInputStream.read(byteArrayFile, 0, byteArrayFile.length);
Log.d(TAG, "Sending...");
bufferedOutputStream.write(byteArrayFile,0,byteArrayFile.length);
bufferedOutputStream.flush();
Receiver is:
bufferedOutputStream=new BufferedOutputStream(new FileOutputStream(file));
byteArray=new byte[fileSize];
int currentOffset = 0;
bytesReaded = bufferedInputStream.read(byteArray,0,byteArray.length);
currentOffset=bytesReaded;
do {
bytesReaded = bufferedInputStream.read(byteArray, currentOffset, (byteArray.length-currentOffset));
if(bytesReaded >= 0){ currentOffset += bytesLeidos;
}
} while(bytesReaded > -1 && currentOffset!=fileSize);
bufferedOutputStream.write(byteArray,0,currentOffset);
You don't state where filesize came from, but there are numerous problems with this code. Too many to mention. Throw it all away and use DataInputStream.readFully(). Or use the following copy loop, which doesn't require a buffer the size of the file, a technique which does not scale, assumes that the file size fits into an int, and adds latency:
byte[] buffer = new byte[8192];
int count;
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
Use this at both ends. If you're sending multiple files via the same connection it gets more complex, but you haven't stated that.

IOException when trying to restore data in BackupAgent in chunks instead of all at once

I've implemented a custom BackupAgent and part of my data are images which are about 1 MB large. When creating the backup, every image is written as a separate entity. On restoring the images, I wanted to read the data in 4K (BUFFER_SIZE) chunks like this and write it to a file like this:
FileOutputStream out = new FileOutputStream(file);
byte[] buffer = new byte[BUFFER_SIZE];
int offset = 0;
int n = 0;
// readEntityData returns 0 when all data of entity is read
while (0 != (n = data.readEntityData(buffer, offset, BUFFER_SIZE))) {
out.write(buffer, 0, n);
offset += n;
}
However, this only reads the first 4K chunk correctly, on the second call of readEntityData an IOException with error code 0xffffffff is thrown.
When I make the buffer as large as the entity's data size and read all the data at once, it works perfectly, but I think it would be safer to use a smaller buffer.
Has anybody experienced something like that? All examples I found read the data at once and not in multiple chunks.

Why is data from Arduino to Android using Android host api garbled?

I followed this tutorial to get started using Android host api with an Arduino board. I am using the Arduino Uno. I am able to transmit data and turn on a LED on the Arduino board and I can receive feedback from the Arduino board. I am trying to write to my Android device over the USB connection from the Arduino board like so:
Serial.print("Test");
I am receiving the Arduino data on the Android side like this:
byte[] buffer = new byte[10];
int bytes;
//try-catch statements omitted for simplicity
bytes = mUsbConnection.bulkTransfer(mUsbEndpointIn, buffer, buffer.length, 0);
Every once and awhile the data will be intact but more often than not, what I receive from the Arduino is a garbled mix of those letters from my original message(t,e,s, and t). Many times only 1 or 2 letters are displayed. If anyone could point me in the right direction or share some similar experience I would be appreciative. Thanks.
Edit
When I print out the data into Logcat, there are multiple copies of the data. For example, if I receive "ste" from Arduino, it will be printed out 2-5 times in Logcat.
I think I found something that works at least temporarily:
public void run(){
int i = 0;
byte[] buffer = new byte[4];
byte[] finalBuffer = new byte[8];
byte[] sendBuffer = new byte[8];
int bytes = 0;
while(true){
try{
bytes = mUsbConnection.bulkTransfer(mUsbEndpointIn, buffer, buffer.length, 0);
if (bytes == EXIT_CMD) {
return;
}
if (bytes > 0){
byte[] temporaryBuffer = new byte[bytes];
System.arraycopy(buffer, 0, temporaryBuffer, 0, bytes);
System.arraycopy(temporaryBuffer, 0, finalBuffer, i, bytes);
i += bytes;
java.util.Arrays.fill(buffer, (byte) 0);
}
//Dollar sign terminates string to indicate end of line
if (finalBuffer[7] == 36){
i = 0;
System.arraycopy(finalBuffer, 0, sendBuffer, 0, sendBuffer.length);
messageHandler.obtainMessage(UsbHostTestActivity.ARDUINO_MESSAGE,
sendBuffer.length, -1, sendBuffer).sendToTarget();
java.util.Arrays.fill(finalBuffer, (byte) 0);
}
I had to send strings that were 8 characters exactly from Arduino and they had to end with a dollar sign($) in order to indicate the end of the line, but the data being passed to my message handler always seemed to be correct. It's not the most robust solution but maybe someone can modify it to make it better or take another approach? Please let me know!

Byte Dropped Over Bluetooth Connection in Android

I am having some issues with bytes being dropped over a bluetooth connection between an android device (Gingerbread 2.3.1) and a PC. The way I receiving the data is in a 2 byte buffer. The values being received is streaming from the PC over a few minutes (values represent a waveform). Here are just a few snippets of code so you can get the idea. The base of my code is from the android bluetooth chat sample code.
BluetoothSocket socket;
...
mmInStream=socket.getInputStream;
...
byte[] buffer= new byte[2];
...
bytes = mmInStream.read(buffer);
Has anyone has issues with this type of thing? The dropped bytes seem to happen at random times while at other times the values received are as expected. I am using a 2 byte buffer because the values I am receiving are 16 bit signed integers. From the PC side of things I am using RealTerm to send the binary files of data.
Is it possible that my buffer is too small and that is causing the dropped bytes?
Thanks
Following up to your answer. You could just use a counter to remember how many bytes already read and compare it to the number wanted and also use it for the index to write the next byte(s). See a C# version at http://www.yoda.arachsys.com/csharp/readbinary.html
public static void ReadWholeArray (Stream stream, byte[] data)
{
int offset=0;
int remaining = data.Length;
while (remaining > 0)
{
int read = stream.Read(data, offset, remaining);
if (read <= 0)
throw new EndOfStreamException
(String.Format("End of stream reached with {0} bytes left to read", remaining));
remaining -= read;
offset += read;
}
}
I have found what the issue is. I want to thank alanjmcf for pointing me in the right direction.
I wasn't checking by bytes variable to see how many bytes were returned from the mmInStream.read(buffer). I was simply expecting that every buffer returned would contain 2 bytes. The way i solved the issue was with the following code after getting the buffer back from the InputStream:
//In the case where buffer returns with only 1 byte
if(lagging==true){
if(bytes==1){
lagging=false;
newBuf=new byte[] {laggingBuf, buffer[0]};
ringBuffer.store(newBuf);
}else if(bytes==2){
newBuf=new byte[] {laggingBuf, buffer[0]};
laggingBuf=buffer[1];
ringBuffer.store(newBuf);
}
}else if(lagging==false){
if(bytes==2){
newBuf = buffer.clone();
ringBuffer.store(newBuf);
}else if(bytes==1){
lagging=true;
laggingBuf=buffer[0];
}
}
This fixed my problem. Any suggestions on a better methodology?

Dowloading a file on android is larger then the size of the file

I'm downloading a video using the below code and maintaining a progress bar to show how much of the download has been completed.
ByteArrayBuffer baf = new ByteArrayBuffer((int)filesize);
long current = 0;
long notificationSize = filesize / 100 * 5;
int notifyCount = 0;
while ((current = inStream.read()) != -1)
{
baf.append((byte) current);
count += current;
//only process update once for each kb
if(count > notificationSize * notifyCount)
{
notifier.processUpdate(count);
notifyCount++;;
}
}
The issue i'm running into is the data being returned from the input stream adds up to be more than the file size. Meaning my progress bar completes before the download completes.
For example i'm download a video that has a file size of 1,849,655 bytes, but the count of the download adds to 228,932,955.
Android Progress bars use a percentage of how much of the process is complete. How do i know how much is complete if the total byte count from the download is more than the size of the file.
Worked out the issue.
When downloading and keeping track of the amount of data that has been downloaded do not use read() from the BufferedInputStream.
Instead use read(buffer, offset, length);
I also changed my code to write out the data to a file as i go instead of storing the data in memory and outputting once all data has come down.
byte[] baf = new byte[filesize];
int actual = 0;
int count = 0;
long notificationSize = filesize / 100 * 5;
int notifyCount = 0;
while (actual != -1)
{
//write data to file
fos.write(baf, 0, actual);
count += actual;
//only process update once for each kb
if(count > notificationSize * notifyCount)
{
notifier.processUpdate(count);
notifyCount++;;
}
actual = inStream.read(baf, 0, filesize);
}
I'm not really sure why read() shows it has read multiple bytes when read() is only meant to read a byte at a time.
If you really want to use read() change
count += current;
to
count++;
It's a rather inefficient way to download though as the number of loops in the while loop is much greater. After some brief performance testing seems slower to download as well (as it needs to write out to the file for each byte instead of a chunk of bytes).

Categories

Resources