Which is better solution get server response data? - android

We usually get data from server response in android development.
/*
* get server response inputStream
*/
InputStream responseInputStream;
Solution1: get response string by multiple read.
/*
* get server response string
*/
StringBuffer responseString = new StringBuffer();
responseInputStream = new InputStreamReader(conn.getInputStream(),"UTF-8");
char[] charBuffer = new char[bufferSize];
int _postion = 0;
while ((_postion=responseInputStream.read(charBuffer)) > -1) {
responseString.append(charBuffer,0,_postion);
}
responseInputStream.close();
Solution2: get response only one read.
String responseString = null;
int content_length=1024;
// we can get content length from response header, here assign 1024 for simple.
responseInputStream = new InputStreamReader(conn.getInputStream(),"UTF-8");
char[] charBuffer = new char[content_length];
int _postion = 0;
int position = responseInputStream.read(charBuffer)
if(position>-1){
responseString = new String(charBuffer,0,position );
}
responseInputStream.close();
Which solution has better performance? why?
Notes: server response json format data that less than 1M bytes.

Why you're reinventing a wheel? ;)
If you're using HttpClient then just use EntityUtils.toString(...).
I guess you're using HttpURLConnection. Then look at EntityUtils.toString(...) from Apache HttpClient - source code. Your first approach is similar to it.
BTW, the second code is worse because:
new String(charBuffer,0,position ) runs garbage collector
In both and even in EntityUtils:
int content_length = 1024; in most cases 8192 is default for socket buffer, so your code might run while loop 8 times more often than it could.

I would recommend the second method IF you do not want to display the amount of data downloaded/transferred . As the object is read as a whole and since the size of your JSON string is comparable to 1M, it will take some time to download. At that time you can, atmost, put up a text for the user saying downloading... You cannot notify the user the amount downloaded.
But if you want to display the amount of data downloaded, use the first method that you gave. Where the you read the data from the server in parts. You can update the UI, with the amount downloaded. For eg 25 % downloaded...
char[] charBuffer = new char[bufferSize];
int _postion = 0;
int i=0;
while ((_postion=responseInputStream.read(charBuffer)) > -1) {
//((i*buffer_size)/content_length) * 100 % completed..
i++;
}
So, I would say the seconds method is better.
BTW Did you consider this?
ObjectInputStream in = new InputStreamReader(conn.getInputStream(),"UTF-8");
if(resposeCode==200)
{
String from_server=(String) in.readObject();
}
Reading the input String as an object. Any object whoe class implements serializable can be passed using ObjectOutputStream and received using ObjectInputStream()

I Think First one is good
Because, in First that will reading your response in char to char method .
Where , Second that will try to read whole response object or as key Filed of Object.
So ,As i think and as per my knowledge First is Better to camper with second.If anyone want to edit then it will truly appreciated.

Related

Cannot VIew the Data Sent By a TCP Packet Sending Program(Packet Server)

I'm trying to develop a small app which receives some data via sockets and based on the data it receives,it prints a toast message for the user.I' getting the data,but the data apparently cannot be read properly.Here is the relavent portion for the same.
int red = -1;
byte[] buffer = new byte[1024]; // a read buffer of 5KiB
byte[] redData;
while ((red = cs.getInputStream().read(buffer)) > -1) {
String redDataTextappend;
redData = new byte[red];
redDataTextappend = new String(redData);
Log.w("Data got",redDataTextappend);
if (redDataTextappend == "hi")
{
//Display Toast message using runonUIThread(new Runnable);
}
else
{//Display Message Using runonUITHread(new Runnable);
}
This code runs on a separate thread as android does not allow networking operations on a separate thread.
The 4 Diamonds is the data displayed by the android studio and cs is the name of the socket which accepts connections.
Thanks.
You are simply printing the String that encodes to zero bytes since you never copy the data that is read in.
It would make more sense to convert the byte array to a hex string if the array contains arbitrary data: see the answers to this question for options for that.
If the array contains the encoding of a String in some charset, for example UTF-8, then do the following:
byte[] redData = Arrays.copyOf(buffer, red);
String redDataTextappend = new String(redData, Charset.forName("UTF-8"));
Log.w("Data got",redDataTextappend);

Append line of text to Azure Block Blob from Android

I want to append a line of text to an existing Azure cloud block blob from an Android device.
In VB.Net I would AcquireLease, getBlockBlobReference, DownloadToFile, add the line on the local files system, UploadToFile, ReleaseLease . Simple and secure, if a bit long-winded.
In Android, it looks a little more tricky. At the moment, my best solution is this:
CloudBlockBlob blob1=container.getBlockBlobReference(chosenOne+".txt");
String proposedLeaseId1 = UUID.randomUUID().toString();
OperationContext operationContext1 = new OperationContext();
blob1.acquireLease(15, proposedLeaseId1, null /*access condition*/,null/* BlobRequestOptions */, operationContext1);
AccessCondition condition = new AccessCondition();
condition.setLeaseID(proposedLeaseId1);
BlobInputStream blobIn = blob1.openInputStream();
blob1.downloadAttributes();
long blobLengthToUse = blob1.getProperties().getLength();
byte[] result = new byte[(int) blobLengthToUse];
blob1.downloadToByteArray(result,0);
blobIn.close();
CloudBlockBlob blob1 = container.getBlockBlobReference(chosenOne+".txt");
String proposedLeaseId1 = UUID.randomUUID().toString();
OperationContext operationContext1 = new OperationContext();
blob1.acquireLease(15, proposedLeaseId1, null /*access condition*/,null/* BlobRequestOptions */, operationContext1);
AccessCondition condition = new AccessCondition();
condition.setLeaseID(proposedLeaseId1);
BlobInputStream blobIn = blob1.openInputStream();
blob1.downloadAttributes();
long blobLengthToUse = blob1.getProperties().getLength();
byte[] result = new byte[(int) blobLengthToUse];
blob1.downloadToByteArray(result,0);
blobIn.close();
blob1.deleteIfExists(DeleteSnapshotsOption.NONE,condition, null, operationContext1);
BlobOutputStream blobOut = blob1.openOutputStream();
//this is a byte by byte write ...
//which is fine ... but no use if you want to replace ...
/*int next = blobIn.read();
while (next != -1) {
blobOut.write(next);
next = blobIn.read();
}*/
blobOut.write(result);
String strTemp="This is just a test string";
blobOut.write(strTemp.getBytes());
blobOut.close();
Apart from being extremely long-winded, I am concerned that as soon as I delete the blob, the lease will go and that I may hit integrity issues. I would appreciate any help in making this code simpler and more secure. I know that Microsoft are planning to introduce append blobs in 3Q 2015, but I want to implement this now.
You can call PutBlock to upload the appended content (the maximum size of each block is 4MB, so please split the appended content into blocks if required), and then call PutBlockList on this blob by passing in the previously committed blocks plus and newly appended blocks.

Volley - download directly to file (no in memory byte array)

I'm using Volley as my network stack in a project I'm working on in Android. Part of my requirements is to download potentially very large files and save them on the file system.
Ive been looking at the implementation of volley, and it seems that the only way volley works is it downloads an entire file into a potentially massive byte array and then defers handling of this byte array to some callback handler.
Since these files can be very large, I'm worried about an out of memory error during the download process.
Is there a way to tell volley to process all bytes from an http input stream directly into a file output stream? Or would this require me to implement my own network object?
I couldn't find any material about this online, so any suggestions would be appreciated.
Okay, so I've come up with a solution which involves editing Volley itself. Here's a walk through:
Network response can't hold a byte array anymore. It needs to hold an input stream. Doing this immediately breaks all request implementations, since they rely on NetworkResponse holding a public byte array member. The least invasive way I found to deal with this is to add a "toByteArray" method inside NetworkResponse, and then do a little refactoring, making any reference to a byte array use this method, rather than the removed byte array member. This means that the transition of the input stream to a byte array happens during the response parsing. I'm not entirely sure what the long term effects of this are, and so some unit testing / community input would be a huge help here. Here's the code:
public class NetworkResponse {
/**
* Creates a new network response.
* #param statusCode the HTTP status code
* #param data Response body
* #param headers Headers returned with this response, or null for none
* #param notModified True if the server returned a 304 and the data was already in cache
*/
public NetworkResponse(int statusCode, inputStream data, Map<String, String> headers,
boolean notModified, ByteArrayPool byteArrayPool, int contentLength) {
this.statusCode = statusCode;
this.data = data;
this.headers = headers;
this.notModified = notModified;
this.byteArrayPool = byteArrayPool;
this.contentLength = contentLength;
}
public NetworkResponse(byte[] data) {
this(HttpStatus.SC_OK, data, Collections.<String, String>emptyMap(), false);
}
public NetworkResponse(byte[] data, Map<String, String> headers) {
this(HttpStatus.SC_OK, data, headers, false);
}
/** The HTTP status code. */
public final int statusCode;
/** Raw data from this response. */
public final InputStream inputStream;
/** Response headers. */
public final Map<String, String> headers;
/** True if the server returned a 304 (Not Modified). */
public final boolean notModified;
public final ByteArrayPool byteArrayPool;
public final int contentLength;
// method taken from BasicNetwork with a few small alterations.
public byte[] toByteArray() throws IOException, ServerError {
PoolingByteArrayOutputStream bytes =
new PoolingByteArrayOutputStream(byteArrayPool, contentLength);
byte[] buffer = null;
try {
if (inputStream == null) {
throw new ServerError();
}
buffer = byteArrayPool.getBuf(1024);
int count;
while ((count = inputStream.read(buffer)) != -1) {
bytes.write(buffer, 0, count);
}
return bytes.toByteArray();
} finally {
try {
// Close the InputStream and release the resources by "consuming the content".
// Not sure what to do about the entity "consumeContent()"... ideas?
inputStream.close();
} catch (IOException e) {
// This can happen if there was an exception above that left the entity in
// an invalid state.
VolleyLog.v("Error occured when calling consumingContent");
}
byteArrayPool.returnBuf(buffer);
bytes.close();
}
}
}
Then to prepare the NetworkResponse, we need to edit the BasicNetwork to create the NetworkResponse correctly (inside BasicNetwork.performRequest):
int contentLength = 0;
if (httpResponse.getEntity() != null)
{
responseContents = httpResponse.getEntity().getContent(); // responseContents is now an InputStream
contentLength = httpResponse.getEntity().getContentLength();
}
...
return new NetworkResponse(statusCode, responseContents, responseHeaders, false, mPool, contentLength);
That's it. Once the data inside network response is an input stream, I can build my own requests which can parse it directly into a file output stream which only hold a small in-memory buffer.
From a few initial tests, this seems to be working alright without harming other components, however a change like this probably requires some more intensive testing & peer reviewing, so I'm going to leave this answer not marked as correct until more people weigh in, or I see it's robust enough to rely on.
Please feel free to comment on this answer and/or post answers yourselves. This feels like a serious flaw in Volley's design, and if you see flaws with this design, or can think of better designs yourselves, I think it would benefit everyone.

JSONObject text must begin with '{' at character 1 of

I had a PHP API which showed a JSON Array, which I then read into an Android Application.
I since moved servers and the android application broke.
I assumed it was the Authentication and thought I would re-build the Android application (Was my first application and thought a re-write could make things better)
For some reason I am now getting this exception error
I read somewhere that I need to parse JSON_FORCE_OBJECT in the PHP json_encode
json_encode($arrMyData, JSON_FORCE_OBJECT);
But I am running PHP 5.2 (Options parameter came out in PHP 5.3)
My code for you to rip into
private void displayAllStories(){
String line;
int intNumStories = 0;
JSONObject arrAllStories;
LinearLayout storiesLayout = (LinearLayout) findViewById(R.id.lyoutStoriesMain);
storiesLayout.removeAllViewsInLayout();
try {
while((line = this.jsonResult.readLine()) != null){
JSONObject arrStories;
arrStories = new JSONObject(line.trim());
intNumStories = Integer.parseInt(arrStories.optString("NumStories"));
arrAllStories = arrStories.getJSONObject("StoryData");
this.strDebug += "We have "+intNumStories+"\n";
}
} catch (IOException e) {
this.strDebug += "Error (3) "+e.getLocalizedMessage()+"\n";
} catch (JSONException e) {
this.strDebug += "Error (4) "+e.getLocalizedMessage()+"\n";
}
}
And the encoded data from the website
{
"NumStories":1,
"StoryData":{
"Story0":{
"ID":"1020",
"OWERNAME":"Alicia",
"STORYMAIN":"Good evening my son was born with bilateral club feet. When he was a week old we started serial casting once a week for 3 months and then he was placed in braces for the next 6 months for a 23 hour period and then for the next 3 months just durning the night. This last visit the doctor said that he needs to have his tendons lengthened and he will go back into cast. After reading all of these articles I am a little scared on what will be best for him. It sounds like the risk of having the surgery are just as heavily weighed as just keeping him in AFO\\'s till he can make his own decision. I would like all advice whether it be positive or negative. Thank you in advance for your help.",
"STORYBRIEF":"Need reassurance that tendon lengthening is the best decision.",
"ADDEDDATE":"2011-12-12 00:51:16",
"CURRENTSTATUS":"n"
}
}
}
Sorry I should add, the code before this which procudes jsonResult is as follows
try{
URL url = null;
URLConnection urlConn = null;
InputStreamReader jsonIsr = null;
BufferedReader jsonBr = null;
//this.strDebug += "URL is "+this.strURL+"\n";
url = new URL(this.strURL);
urlConn = url.openConnection();
jsonIsr = new InputStreamReader(urlConn.getInputStream());
jsonBr = new BufferedReader(jsonIsr, 8192);
this.jsonResult = jsonBr;
return true;
}catch(MalformedURLException e){
this.strDebug += "JSON Error (1) "+e.getLocalizedMessage()+"\n";
}catch(IOException e){
this.strDebug += "JSON Error (2) "+e.getLocalizedMessage()+"\n";
}
}else{
strDebug = "NO URL Passed to JSON\n";
}
// EDIT 2
For those who asking
The error is as the title says
Error (4) A JSONObject text must being with '{' at character 1 of {"NumStories":1, "StoryData":........
Your code assumes that whole JSON data comes on one line: it iterates with readLine() but creates a new JSON object every time.
You are reading the data line by line and trying to convert each line into a JSON object. That won't work because a single line just contains a fragment of a complete JSON object.
I don't know what type jsonResult has. But you'll probably want to read the whole thing at once.
Your old web application probably produced JSON data without line break so a single line would contain a full JSON object.
i think you read the json file line by line and pass to the json object you should like this way the whole string you have to pass to the json object for parsing than only you getting the json
JSONObject arrStories = new JSONObject(jsonResult);
now get the object like this way
intNumStories = Integer.parseInt(arrStories.getString("NumStories"));
This code is going to break, if object takes more than one line (apparemtly it does). Your choices are:
Collect all the strings into string builder, the parse from this string ( http://developer.android.com/reference/org/json/JSONTokener.html )
Take GSON or my databinding layer ( https://github.com/ko5tik/jsonserializer ) and just parse stream into object.

Android String Parsing

I am writing an android app that recieves data over bluetooth. The bytes comming in can be of any size example: 00023>024935928598235>9284>
As you can see each set is seperated by ">". The data comes in extremely fast. I would like some ideas for an implementation. See my problem is that I need to read the data into a byte array that can and then convert it to a string and split them according to the delimeter of ">".
so in the above example:
00023
024935928598235
9284
If i set byte[] data = new byte[8] then when reading the incomming data it might get 00023>02 which is not what i want. I'm not sure how to implement something like this. Any ideas?
Here's one approach. You'll have to implement the readDataFromBluetooth() and somehow set dataAvailable, but this should get you on the right track.
byte[] data = new byte[1024];
List<String> chunks = new LinkedList<String>();
StringBuilder chunk = new StringBuilder();
while (dataAvailable) {
data = readDataFromBluetooth();
for (byte b : data) {
if (b == '<') {
chunks.add(chunk.toString());
chunk.setLength(0);
} else {
chunk.append(b);
}
}
}
if (chunk.length() > 0)
chunks.add(chunk.toString());
I would recommend using a buffered stream, but maybe a bit bigger that 8 bytes, as you suggest, and the read one and one character from the beginning of the stream, accumulating the string. When you encounter a ">", send the value you have accumulated off to a queue for a background thread processing. Use standard producer/consumer implementation techniques (e.g. the Monitor pattern) to communicate via the queue.

Categories

Resources