I want to ask if there's some way to split data obtained from server by some unique separator.
Here is an example:
I use AsyncTask to send data to server and then I use echo command for sending those back to my application and in onPostExecute I split these data to needed result.
So let's say, that I want to get from server data for Name and Surname, so echo command on server will look like this: echo $name."&".$surname;
And then in onPostExecute I will split this data by "&" separator, but problem occurs when user writes to name or surname my separator "&" which I am using for split.
How can I avoid this issue?
Look into using JSON. It's a life saver for sending data.
Android has native JSON support using a JSONObject.
Documentation
It essentially provides a formatter and parser for information placed within the object that are then accessible via keywords.
To write a json:
public String writeJSON() {
JSONObject object = new JSONObject();
try {
object.put("name", "John");
object.put("surname", "Doe");
return object.toString();
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
This will return a string that looks like:
{"name":"John","surname":"Doe"}
To read:
public void readJSON(String jsonString){
try {
JSONObject object = new JSONObject(jsonString);
String name = object.getString("name");
String surname = object.getString("surname");
} catch (JSONException e){
e.printStackTrace();
}
}
You need to escape the character you are using to separate the different entries in the content you are transmitting [1]. For example:
My\&FirstName&MySecondName (In this case \ is used as escape character)
However, you don't need to reinvent all this stuff. There are several formats that you could use to transmit your data:
json
xml
csv
[1] https://en.wikipedia.org/wiki/Escape_character
Related
I am building a device that can communicate between a vehicle ECU, Arduino, and Android device. The end goal is to get information from the car to the user's phone.
I currently have the following Arduino code that collects vehicle data via the OBD-II port and sends over the serial as JSON:
#include <Wire.h>
#include <OBD.h>
COBDI2C obd;
char vin[64];
int distance;
int velocity;
int runtime;
String json;
void setup() {
Serial.begin(9600);
obd.begin();
while(!obd.init());
}
void loop() {
obd.getVIN(vin, sizeof(vin));
delay(100);
obd.readPID(PID_DISTANCE, distance);
delay(100);
obd.readPID(PID_SPEED, velocity);
delay(100);
obd.readPID(PID_RUNTIME, runtime);
delay(100);
json = "{\"vin\":\"";
json.concat(vin);
json.concat("\",\"distance\":\"");
json.concat(distance);
json.concat("\",\"speed\":\"");
json.concat(velocity);
json.concat("\",\"runtime\":\"");
json.concat(runtime);
json.concat("\"}");
Serial.print(json);
delay(5000);
}
This would print a string such as "{\"vin\":\"3VWJM71K89M02\",\"distance\": \"19478\",\"speed\":\"0\",\"runtime\":\"216\"}" over a USB connection to an Android device. I have a method that is called on the Android device when USB activity occurs:
public void onReceivedData(byte[] result) {
String dataStr;
try {
dataStr = new String(result, "UTF-8");
dataStr = dataStr.replaceAll("[\\n\\r\\s]+", "");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
try {
driveData = new JSONObject(dataStr);
updateVehicle(driveData);
} catch(JSONException e) {
e.printStackTrace();
}
}
For some reason, the resulting byte array can be converted into a string with no errors, yet is oddly populated with random line breaks and whitespaces, which is why I used replaceAll() to remove these. When I try to create a JSONObject from the string (using the org.json library) I get errors. However, when I append the original string to a textView, I get something that appears to be very valid JSON:
{"vin":"3VWJM71K89M02","distance":"19478","speed":"0","runtime":"216"}
Next, I tried constructing a JSONObject using the exact string constructed on the Arduino earlier, such as so:
try {
driveData = new JSONObject("{\"vin\":\"3VWJM71K89M02\",\"distance\": \"19478\",\"speed\":\"0\",\"runtime\":\"216\"}");
updateVehicle(driveData);
} catch(JSONException e) {
e.printStackTrace();
}
This threw me no errors at all. So what am I doing wrong that the original data sent via USB is not as valid as actual data that arrives?
Update:
By request I have some error codes from the Android device. Unfortunately, it seems like a chain reaction, so I am providing some of the first ones:
org.json.JSONException: Unterminated string at character 4 of {"vi
org.json.JSONException: End of character input at character 0 of
org.json.JSONException: Value n" of typejava.lang.String cannot be converted to JSONObject
org.json.JSONException: End of character input at character 0 of
org.json.JSONException: Unterminated string at character 7 of "3VMJM7
org.json.JSONException: ...
As gre_gor mentioned in the comments, the event receiving the USB data was not capturing the entire message from the Arduino in a single call. I found that if you keep a running string of the all the USB data and check that string for JSON syntax each call, you eventually get a valid JSON object. Then just reset the string and keep listening.
So, my new code would look like:
public String usbStr = "";
public JSONObject driveData;
...
public void onReceivedData(byte[] result) {
String dataStr;
try {
dataStr = new String(result, "UTF-8");
dataStr = dataStr.replaceAll("[\\n\\r\\s]+", "");
usbStr = usbStr.concat(dataStr);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
try {
driveData = new JSONObject(dataStr);
usbStr = "";
updateVehicle(driveData);
} catch(JSONException e) {
e.printStackTrace();
}
}
I want to send an JSONObject using retrofit 2 to server and i am sending this kind of json object :
{"Order Summary":
"[
{
\ "ProductName\":\"Wine\",
\"ProductPrice\":\"500\",
\"ProductQuantity\":\"2\",
\"ProductCost\":\"1000\",
\"SellerId\":\"2\"
},
{
\"ProductName\":\"Whiskey\",
\"ProductPrice\":\"1000\",
\"ProductQuantity\":\"1\",
\"ProductCost\":\"1000\",
\"SellerId\":\"1\"
}
]"}
due to which i'm unable to parse the json object
and this is the source code iam using :-
private void loadCart()
{
Cursor cursor = dbHelper.getCarProducts();
cursor.moveToFirst();
do {
JSONObject product = new JSONObject();
try {
product.put("Sellerid",cursor.getString(cursor.getColumnIndex("_Sellerid")));
product.put("ProductCost",cursor.getString(cursor.getColumnIndex("_Cost")));
product.put("ProductQuantity",cursor.getString(cursor.getColumnIndex("_Quantity")));
product.put("ProductPrice",cursor.getString(cursor.getColumnIndex("_Price")));
product.put("ProductName",cursor.getString(cursor.getColumnIndex("_Name")));
userCart.put(product);
} catch (JSONException e) {
e.printStackTrace();
}
}while(cursor.moveToNext());
Cart = new JSONObject();
try
{
Cart.put("OrderSummary",userCart.toString());
}
catch (Exception ex)
{}}
could someone tell me how to rectify this error ?
Here is your mistake
Cart.put("OrderSummary", userCart.toString());
You get pure JSON Array but why are you converting it to String?
Use,
Cart.put("OrderSummary", userCart); // remove .toString()
Edit
By checking your server side code, I think the problem is in index.php file (I'm not expert in PHP)
$requestedData = $response->getBody();
Instead of $response you should use $request object. In order to fix that refer this StackOverflow thread or refer this official doc of Slim Framework.
And to send JSON response from Slim Framework to refer this StackOverflow thread.
Note: While declaring Java variables/objects try to respect Java varibales/method naming conventions. Instead of Cart use cart, this eliminates ambiguity.
I've written a simple app the uses the Android Wear Messaging API. I followed a number of guides that all use a similar style of code for sending the message with some data which should be in byte[] form.
The code sending the message is
Wearable.MessageApi.sendMessage(client, nodeId, message, "test".getBytes());
and the receiving code is
final String messageData = new String(messageEvent.getData());
This seems to fit with a number of different guides and some of the official documentation - however the variable messageData ends up containing [B#4b0ad22 rather than test which is the data that was sent.
I've also tried explicit encoding/decoding with
String messageData = new String(messageEvent.getData(), "UTF-8");
but that throws a java.io.UnsupportedEncodingException
What's going wrong with the encoding or decoding?
You have to define the encoding/decoding but also wrap it in a try/catch block so the receiving code looks like this,
String messageData = "";
try {
messageData = new String(messageEvent.getData(), "UTF-8");
}
catch(Exception e)
{
Log.e("DecodingError", e.toString());
}
The sending code looks like this;
try {
Wearable.MessageApi.sendMessage(client, nodeId, message, "test".getBytes("UTF-8"));
}
catch(Exception e)
{
Log.e("EncodingError", e.toString());
}
So, I am trying to retrieve JSON data from a webservice. It usually works. It doesn't work, however, if the value of a certain variable has double quotations as part of its content. For example, if I am parsing this data:
{"ID":"1057","PlaceTitle":"Place 1","PlaceDetails":"George Bush once said "This is the best dang place in the world""}
I get an error on "George bush... because it is trying to detect it as a variable because of the quotes, I believe. This exception is thrown:
org.json.JSONException: Unterminated object at character 1418 of
So what I want to do is "if this exception is thrown, treat it as content within PlaceDetails, and continue on." Any idea how I can accomplish this?
Code:
try {
JSONArray jArray = new JSONArray(result);
for (int i = 0; i < jArray.length(); i++) {
final JSONObject json = jArray.getJSONObject(i);
try {
arrayOfLocationss.add(new Location(context,
json.getInt("ID") json
.getString("PlaceTitle"), json
.getString("PlaceDetails"));
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
You need to fix the webservice so it returns properly formatted JSON. Quotes inside of strings need to be escaped with a backslash:
{"ID":"1057","PlaceTitle":"Place 1","PlaceDetails":"George Bush once said \"This is the best dang place in the world\""}
Why dont you escape all double quotes when you use getString? Try something like
arrayOfLocationss.add(new Location(context,
json.getInt("ID") json
.getString("PlaceTitle").toString().replaceAll("\"", "\\\""),
json.getString("PlaceDetails").toString().replaceAll("\"", "\\\""));
I'm new to Android development and I will appreciate any help I can get.
I'm designing an app that at some point needs to ask user for his Friends' names in order to work with those names later on, i.e those names will be used in drop-down lists and will be displayed at a separate View.
My question is: what is the best way to efficiently store those names and then be able to get access to them for reading, editing and deleting? The amount of names will not be big (at most 20 items).
In response to the comment about adding more info:
I need a user to specify list of names (strings) that will be used in 2 different Android Activities:
1) This list of names will be used in a Spinner that is a part of an application form
2) This list of names will be used on a separate Activity designed for Manipulating (Editing and Deleting) of existing items and adding new ones.
I also need that after manipulations (editing, deleting and creating new items) with this list changes took place in Both Activities. This list should be available after user exits the app, so as I understand it should be stored somewhere in Internal Storage.
I hate when people answer a question by just posting the link to the docs, so I won't do that.
I will post the link to the docs AND provide an answer:
DOCS: http://developer.android.com/guide/topics/data/data-storage.html
(it is actually a good read, not too long, and good to know what your options are).
It looks to me you need to save an ArrayList or something, and you are saying 20 names would be the maximum amount, so I would say you have 3 viable options, which I present here, ordered in ascending order of simplicity using my humble opinion as a comparator:
1- InternalStorage
2- SharedPreferences
3- Very interesting way I just found while researching one of the options to help you, and I will definatelly use this when I need to save a small array of data...
So the steps I would recomend are: put the names in your favourite collection object (ArrayList, HashSet, etc), then refer to those examples for the methods cited above, respectivelly:
1- https://stackoverflow.com/a/22234324/367342 (YES, this a link to a answer given on this thread, I voted it up, I feel better for cheating now).
2- Save ArrayList to SharedPreferences
3- https://stackoverflow.com/a/5703738/367342 <- this
- Convert your data to a JSONObject
- Convert it to a string
- Save this string using shared preferences
- Read it later as a jsonobject
Example on 3 (untested, sorry):
//Convert the ArrayList to json:
JSONObject json = new JSONObject();
json.put("uniqueArrays", new JSONArray(items));
//Make it into a string
String myLittleJason = json.toString();
//save it to the shared preferences
PreferenceManager.getDefaultSharedPreferences(context).edit().putString("KEY_TO_THE_NAMES_OF_MY_DEAR_FRIENDS", myLittleJason).commit();
//Loading it back from the preferences
String loadedJsonString = PreferenceManager.getDefaultSharedPreferences(context).getString("KEY_TO_THE_NAMES_OF_MY_DEAR_FRIENDS", "I have no friends, this is the default string returned if the key was not found, so, jokes aside, better make this a empty JSON string");
//making it into a JSON again
JSONObject loadedJson = new JSONObject(loadedJsonString);
//Converting the Json back into a ArrayList
ArrayList items = loadedJson.optJSONArray("uniqueArrays");
I loved that JSON approach, if you like it too, upvote the original (too ;) ) https://stackoverflow.com/a/5703738/367342
If you are going to store only 20 items, maybe the best way is to write and read a file.
public void writeItems(String fileName) {
final String ls = System.getProperty("line.separator");
BufferedWriter writer = null;
try {
writer =
new BufferedWriter(new OutputStreamWriter(openFileOutput(fileName,
Context.MODE_PRIVATE)));
writer.write("Item 1" + ls);
writer.write("Item 2" + ls);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void readItems(String fileName) {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(openFileInput(fileName)));
String line;
while ((line = input.readLine()) != null) {
//do something
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (input != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
openFileInput and openFileOutput reference : http://developer.android.com/reference/android/content/Context.html#openFileInput(java.lang.String)
You have many options but I will give you two options:
SharedPreferences
SQLLite
If it's temporary and doesn't require intense data manipulation, I would go with SharedPreferences as it's easier to setup and easy to use and recycle.