Everytime someone makes a transaction in my app I would like to save it to local storage using json / gson. I believe I am nearly there but my problem is correctly formatting the json file every time I write to it.
I would like to append to the file every time I create a Transaction object, and then at some point read every Transaction object from the file for display in a list. Here is what I have so far:
public void saveTransaction(Transaction transaction)
throws JSONException, IOException {
Gson gson = new Gson();
String json = gson.toJson(transaction);
//Write the file to disk
Writer writer = null;
try {
OutputStream out = mContext.openFileOutput(mFilename, Context.MODE_APPEND);
writer = new OutputStreamWriter(out);
writer.write(json);
} finally {
if (writer != null)
writer.close();
}
}
My transaction object has an amount, a user id and a boolean, writing with this code I can read the following json String:
{"mAmount":"12.34","mIsAdd":"true","mUID":"76163164"}
{"mAmount":"56.78","mIsAdd":"true","mUID":"76163164"}
I am reading these values like so but can only read the first one (I guess because they are not in an array / properly formatted json object):
public ArrayList<Transaction> loadTransactions() throws IOException, JSONException {
ArrayList<Transaction> allTransactions = new ArrayList<Transaction>();
BufferedReader reader = null;
try {
//Open and read the file into a string builder
InputStream in = mContext.openFileInput(mFilename);
reader = new BufferedReader(new InputStreamReader(in));
StringBuilder jsonString = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
//Line breaks are omitted and irrelevant
jsonString.append(line);
}
//Extract every Transaction from the jsonString here -----
} catch (FileNotFoundException e) {
//Ignore this one, happens when launching for the first time
} finally {
if (reader != null)
reader.close();
}
return allTransactions;
}
im not sure i understand your question, but have you tried creating a TransactionCollection object that has an ArrayList<Transaction> transactions
and create your json from the TransactionCollection object instead of each transaction?
Related
This is related to a situation I find myself in working with saving text files in Unity on Android, then reading them in native Android.
One of the files we read is a HMACMD5 signature, created with the code,
byte[] bData = System.Text.Encoding.UTF8.GetBytes (data);
byte[] bKey = System.Text.Encoding.UTF8.GetBytes (key);
using (HMACMD5 hmac = new HMACMD5(bKey)) {
byte[] signature = hmac.ComputeHash (bData);
return System.Convert.ToBase64String (signature);
}
And then written to the phone with,
public static void SaveText (string path, string data) {
using (FileStream fs = new FileStream(path, FileMode.Create)) {
using (StreamWriter sw = new StreamWriter(fs)) {
sw.Write (data);
}
}
}
The other string we're saving is a JSON string dump. The signature has a newline character at the end of the string, but the JSON string doesn't. I know I can manually add one, but this question is about reading the accurate file contents.
On Android, based on previous SO answers, I read the file with,
String readFile(File file) {
StringBuilder text = new StringBuilder();
try {
BufferedReader br = new BufferedReader(new FileReader(file));
String line;
while ((line = br.readLine()) != null) {
text.append(line);
text.append("\n");
}
br.close();
}
catch (IOException e) {
MyLogger.e(LOG_TAG, "Error opening file " + file.getPath(), e);
}
return text.toString();
}
I'm manually adding the newline character after every line, but if I do this, I don't accurately read the JSON file, which doesn't have a newline character at the end. If I don't add the newline, I don't accurately read the signature file, which does.
You better then do not use readLine() but read().
How do I create a "JSONObject" from a local JSON file inside my "raw" folder.
I have the following JSON file under the "raw" folder of my android app project. The file is called "app_currencies.json". I need the information contained on this file as an object in my class. Below are the file contents:
{
"EUR": { "currencyname":"Euro", "symbol":"EUR=X", "asset":"_European Union.png"},
"HTG": { "currencyname":"Haitian Gourde", "symbol":"HTG=X", "asset":"ht.png"},
"WST": { "currencyname":"Samoan Tala", "symbol":"WST=X", "asset":"ws.png"},
"GBP": { "currencyname":"British Pound", "symbol":"GBP=X", "asset":"gb.png"}
}
I think what I need is to use the following:
//Get data from Json file and make it available through a JSONObject
InputStream inputStream = getResources().openRawResource(R.raw.app_currencies.json);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
JSONObject jObject = new JSONObject;
jObject is what I need. I think I need an InputStream, ByteArrayOutputStream so that I can store it into JSONObject... the problem is that I'm not sure how to implement this code properly so that I can access the data? If any of you could give detailed instructions on how to do this, I would really appreciate it.
The following code reads a json file into a Json Array. See if it helps. Note, the file is stored in Assets instead
BufferedReader reader = null;
try {
// open and read the file into a StringBuilder
InputStream in =mContext.getAssets().open(mFilename);
reader = new BufferedReader(new InputStreamReader(in));
StringBuilder jsonString = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
// line breaks are omitted and irrelevant
jsonString.append(line);
}
// parse the JSON using JSONTokener
JSONArray array = (JSONArray) new JSONTokener(jsonString.toString()).nextValue();
// do something here if needed from JSONObjects
for (int i = 0; i < array.length(); i++) {
}
} catch (FileNotFoundException e) {
// we will ignore this one, since it happens when we start fresh
} finally {
if (reader != null)
reader.close();
}
I am building an app that connects to a blog then gathers the data in JSON. Currently I amgeting this error (sorry about all JSON dat not sure whether to include):
Exception Caught
org.json.JSONException: Unterminated string at character 6564 of {"status":"ok","count":20,"count_total":1727,"pages":87,"posts":[{"id":23419,"url":"http:\/\/blog.teamtreehouse.com\/happy-mothers-day-ones-whove-shaped-web-careers","title":"Happy Mother\u2019s Day! Thanks, Mom, for Helping Us Learn","date":"2014-05-08 11:00:29","author":"Ryan Brinks","thumbnail":"http:\/\/blog.teamtreehouse.com\/wp-content\/uploads\/2014\/05\/mothers-dayHaik-Avanian-150x150.jpg"},{"id":23412,"url":"http:\/\/blog.teamtreehouse.com\/technology-brings-people-attitude-public-data-projects","title":"Public Data Brings ‘We the People’ Attitude to Technology","date":"2014-05-08 10:08:22","author":"Kelley King","thumbnail":"http:\/\/blog.teamtreehouse.com\/wp-content\/uploads\/2014\/05\/adoptahydrant-150x150.jpg"},{"id":23409,"url":"http:\/\/blog.teamtreehouse.com\/help-students-learn-computer-programming","title":"A Push for More Computer Programming in Public Schools","date":"2014-05-07 15:50:51","author":"Tim Skillern","thumbnail":"http:\/\/blog.teamtreehouse.com\/wp-content\/uploads\/2014\/05\/student-computer-class-woodleywonderworks-flickr-150x150.jpg"},{"id":23398,"url":"http:\/\/blog.teamtreehouse.com\/military-veterans-finding-technology-jobs-secure-bet","title":"Technology Jobs a Secure Bet for Military Veterans","date":"2014-05-06 13:45:13","author":"Anayat Durrani","thumbnail":"http:\/\/blog.teamtreehouse.com\/wp-content\/uploads\/2014\/05\/durrani-kopser-150x150.jpg"},{"id":23407,"url":"http:\/\/blog.teamtreehouse.com\/typography-sidebars-style-guides-treehouse-show-ep-89","title":"Typography, Sidebars, Style Guides | The Treehouse Show Ep 89","date":"2014-05-06 10:15:43","author":"Jason Seifer","thumbnail":null},{"id":23393,"url":"http:\/\/blog.teamtreehouse.com\/5-tips-creating-perfect-web-design-portfolio","title":"5 Tips for Creating the Perfect Web Design Portfolio","date":"2014-05-05 17:55:08","author":"Nick Pettit","thumbnail":"http:\/\/blog.teamtreehouse.com\/wp-content\/uploads\/2014\/05\/how-to-make-a-website-150x150.jpg"},{"id":23381,"url":"http:\/\/blog.teamtreehouse.com\/writing-tips-better-business-marketing","title":"11 Rules for Better Writing, or How Not to Use a Thesaurus","date":"2014-05-01 18:38:32","author":"Tim Skillern","thumbnail":"http:\/\/blog.teamtreehouse.com\/wp-content\/uploads\/2014\/05\/pencils-wikimedia-150x150.jpg"},{"id":23387,"url":"http:\/\/blog.teamtreehouse.com\/web-job-perks-unlimited-vacation-catered-lunch-part-amazing-opportunity-weebly-com-programmer","title":"Web Job Perks: Unlimited Vacation, Catered Lunch Part of \u2018Amazing Opportunity\u2019 for Weebly.com Programmer","date":"2014-05-01 17:00:28","author":"Jimmy Alford","thumbnail":"http:\/\/blog.teamtreehouse.com\/wp-content\/uploads\/2014\/05\/weebly-guy0-2-150x150.jpg"},{"id":23375,"url":"http:\/\/blog.teamtreehouse.com\/illustrator-ben-obrien-inspiration","title":"Noted Illustrator Ben O’Brien Talks About Finding Inspiration, Taking Chances","date":"2014-04-29 18:13:58","author":"Gillian Carson","thumbnail":"http:\/\/blog.teamtreehouse.com\/wp-content\/uploads\/2014\/04\/obrien3-150x150.jpg"},{"id":23373,"url":"http:\/\/blog.teamtreehouse.com\/gulp-sketch-3-bud-treehouse-show-episode-88","title":"Gulp | Sketch 3 | Bud | The Treehouse Show Episode 88","date":"2014-04-29 15:29:20","author":"Jason Seifer","thumbnail":null},{"id":23361,"url":"http:\/\/blog.teamtreehouse.com\/flexbox-next-generation-css-layout-arrived","title":"Flexbox: The Next Generation of CSS Layout Has Arrived","date":"2014-04-29 11:53:40","author":"Nick Pettit","thumbnail":"http:\/\/blog.teamtreehouse.com\/wp-content\/uploads\/2014\/04\/Screen-Shot-2014-04-28-at-1.00.03-AM-150x150.png"},{"id":23364,"url":"http:\/\/blog.teamtreehouse.com\/help-wanted-women-color-needed-technology-web-jobs","title":"Help Wanted: Women of Color Needed in Technology, Web Jobs","date":"2014-04-28 12:28:56","author":"Anayat Durrani","thumbnail":"http:\/\/blog.teamtreehouse.com\/wp-content\/uploads\/2014\/04\/poorn
This is where teh error is being caught:
public void updateList() {
if (mBlogData == null) {
// TODO: Handle Error
}
else {
try {
Log.d(TAG, mBlogData.toString(2));
}
catch (JSONException e) {
Log.e(TAG, "Exception Caught", e);
}
}
}
I am not sure what is causing this error so any suggestions are welcome. I can provide more code if needed. Thank You.
Just wanted to add to eMad's answer which helped me solve the same problem you are having. I hope this helps anybody who is to come after me because this darn bug killed 2 hours of my day (or night, I'm nocturnal). Well, with out further (ado? adieu?), here you go : P.S. the below code will go in your private class GetBlogPostsTask AsynnTask...
protected JSONObject doInBackground(Object... arg0) {
int responseCode = -1;
JSONObject jsonResponse = null;
try {
//set API URL
URL blogFeedUrl = new URL("http://blog.teamtreehouse.com/api/get_recent_summary/? count=" + NUMBER_OF_POSTS);
//open URL connection
URLConnection connection = blogFeedUrl.openConnection();
//create BufferedReader to read the InputStream return from the connection
BufferedReader in = new BufferedReader(
new InputStreamReader ( connection.getInputStream() )
);
//initiate strings to hold response data
String inputLine;
String responseData = "";
//read the InputStream with the BufferedReader line by line and add each line to responseData
while ( ( inputLine = in.readLine() ) != null ){
responseData += inputLine;
}
//check to make sure the responseData is not empty
if( responseData!= "" ){
/*initiate the jsonResponse as a JSONObject based on the string values added
to responseData by the BufferedReader */
jsonResponse = new JSONObject(responseData);
}
/*return the jsonResponse JSONObject to the postExecute() method
to update the UI of the context */
return jsonResponse;
}
catch (MalformedURLException e) {
Log.e(TAG, "Exception caught: ", e);
}
catch (IOException e) {
Log.e(TAG, "Exception caught: ", e);
}
catch (Exception e) {
Log.e(TAG, "Exception caught: ", e);
}
return jsonResponse;
}
#Override
protected void onPostExecute(JSONObject result) {
/* set the class' member JSONObject mBlogData to the result
to be used by the handleBlogResponse() method to update the UI */
mBlogData = result;
/*call the handleBlogResponse() method to update the UI with the result of this AsyncTask
which will be a JSONObject in best case scenario or a null object in worst case */
handleBlogResponse();
}
A friend of mine brought me a code that was generating the same output as yours. I think this is the solution that you're looking for. Given code is
// inside the class which connects to URL (Probably MainList)
InputStream inputStream = connection.getInputStream();
Reader reader = new InputStreamReader(inputStream);
int contentLength = connection.getContentLength();
char[] charArray = new char[contentLength];
reader.read(charArray);
String responseData = new String(charArray);
jsonResponse = new JSONObject(responseData);
But don't know why using above code, you either not get the full string or get the ContentLenght right but the last few characters aren't received properly. Use following code instead which reads complete response:
URLConnection yc = blogFeedUrl.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(
yc.getInputStream()));
String inputLine;
responseData = "";
while ((inputLine = in.readLine()) != null) // read till you can receive any data
responseData += inputLine;
in.close();
I am developing an android app in netbeans. I am trying to read CSV file using opencsv. When I put the file in resources folder and try to read it from there, there's an error while building saying invalid resource directory. Where should I store csv file so that it can be read each time the app starts?
you should put csv file in assets folder ..
InputStreamReader is = new InputStreamReader(getAssets()
.open("filename.csv"));
BufferedReader reader = new BufferedReader(is);
reader.readLine();
String line;
while ((line = reader.readLine()) != null) {
}
Some advices;
Create an object for holding one row data into the csv. ( Ex: YourSimpleObject . It provides you to manage the data easily.)
Read file row by row and assign to object. Add the object to list. (Ex: ArrayList<YourSimpleObject >)
Code:
private void readAndInsert() throws UnsupportedEncodingException {
ArrayList<YourSimpleObject > objList= new ArrayList<YourSimpleObject >();
AssetManager assetManager = getAssets();
InputStream is = null;
try {
is = assetManager.open("questions/question_bank.csv");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
BufferedReader reader = null;
reader = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
String line = "";
StringTokenizer st = null;
try {
while ((line = reader.readLine()) != null) {
st = new StringTokenizer(line, ",");
YourSimpleObject obj= new YourSimpleObject ();
//your attributes
obj.setX(st.nextToken());
obj.setY(st.nextToken());
obj.setZ(st.nextToken());
obj.setW(st.nextToken());
objList.add(sQuestion);
}
} catch (IOException e) {
e.printStackTrace();
}
}
As an alternative, take a look at uniVocityParsers. It provides a vast number of ways to parse delimited files. The example bellow loads a Csv File (see in the picture below) from a res/raw folder into a InputStream object, and read it in a colunar manner (a map where key=Column & value=ColumnValues).
calendario_bolsa.csv
//Gets your csv file from res/raw dir and load into a InputStream.
InputStream csvInputStream = getResources().openRawResource(R.raw.calendario_bolsa);
//Instantiate a new ColumnProcessor
ColumnProcessor columnProcessor = new ColumnProcessor();
//Define a class that hold the file configuration
CsvParserSettings parserSettings = new CsvParserSettings();
parserSettings.getFormat().setLineSeparator("\n");
parserSettings.setHeaderExtractionEnabled(true);
parserSettings.setProcessor(columnProcessor);
//Creates a new CsvParser, passing the settings into its construtor:
CsvParser csvParser = new CsvParser(parserSettings);
//Calls parse method, instantiating an InputStreamReader, passing to its constructor the InputStream object
csvParser.parse(new InputStreamReader(csvInputStream));
//Gets the csv data as a Map of Column / column values.
Map<String, List<String>> columnarCsv = columnProcessor.getColumnValuesAsMapOfNames();
To add univocityParsers into your Android Project:
compile group: 'com.univocity', name: 'univocity-parsers', version: '2.3.0'
Using opencsv:
InputStream is = context.getAssets().open(path);
InputStreamReader reader = new InputStreamReader(is, Charset.forName("UTF-8"));
List<String[]> csv = new CSVReader(reader).readAll();
you may use this code
try {
InputStream csvStream = assetManager.open(CSV_PATH);
InputStreamReader csvStreamReader = new InputStreamReader(csvStream);
CSVReader csvReader = new CSVReader(csvStreamReader);
String[] line;
// throw away the header
csvReader.readNext();
while ((line = csvReader.readNext()) != null) {
questionList.add(line);
}
} catch (IOException e) {
e.printStackTrace();
}
you may download csvreader file from
http://sourceforge.net/projects/opencsv/files/latest/download
and import in your project
Hi there i'm creating my first android app and i'm wanting to know what is the best and most efficient way of parsing a JSON Feed from a URL.Also Ideally i want to store it somewhere so i can keep going back to it in different parts of the app. I have looked everywhere and found lots of different ways of doing it and i'm not sure which to go for. In your opinion whats the best way of parsing json efficiently and easily?
I'd side with whatsthebeef on this one, grab the data and then serialize to disk.
The code below shows the first stage, grabbing and parsing your JSON into a JSON Object and saving to disk
// Create a new HTTP Client
DefaultHttpClient defaultClient = new DefaultHttpClient();
// Setup the get request
HttpGet httpGetRequest = new HttpGet("http://example.json");
// Execute the request in the client
HttpResponse httpResponse = defaultClient.execute(httpGetRequest);
// Grab the response
BufferedReader reader = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent(), "UTF-8"));
String json = reader.readLine();
// Instantiate a JSON object from the request response
JSONObject jsonObject = new JSONObject(json);
// Save the JSONOvject
ObjectOutput out = new ObjectOutputStream(new FileOutputStream(new File(getCacheDir(),"")+"cacheFile.srl"));
out.writeObject( jsonObject );
out.close();
Once you have the JSONObject serialized and save to disk, you can load it back in any time using:
// Load in an object
ObjectInputStream in = new ObjectInputStream(new FileInputStream(new File(new File(getCacheDir(),"")+"cacheFile.srl")));
JSONObject jsonObject = (JSONObject) in.readObject();
in.close();
Your best bet is probably GSON
It's simple, very fast, easy to serialize and deserialize between json objects and POJO, customizable, although generally it's not necessary and it is set to appear in the ADK soon. In the meantime you can just import it into your app. There are other libraries out there but this is almost certainly the best place to start for someone new to android and json processing and for that matter just about everyone else.
If you want to persist you data so you don't have to download it every time you need it, you can deserialize your json into a java object (using GSON) and use ORMLite to simply push your objects into a sqlite database. Alternatively you can save your json objects to a file (perhaps in the cache directory)and then use GSON as the ORM.
This is pretty straightforward example using a listview to display the data. I use very similar code to display data but I have a custom adapter. If you are just using text and data it would work fine. If you want something more robust you can use lazy loader/image manager for images.
Since an http request is time consuming, using an async task will be the best idea. Otherwise the main thread may throw errors. The class shown below can do the download asynchronously
private class jsonLoad extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
String response = "";
for (String url : urls) {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse execute = client.execute(httpGet);
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(new InputStreamReader(content));
String s = "";
while ((s = buffer.readLine()) != null) {
response += s;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return response;
}
#Override
protected void onPostExecute(String result) {
// Instantiate a JSON object from the request response
try {
JSONObject jsonObject = new JSONObject(result);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
File file = new File(getApplicationContext().getFilesDir(),"nowList.cache");
try {
file.createNewFile();
FileOutputStream writer = openFileOutput(file.getName(), Context.MODE_PRIVATE);
writer.write(result);
writer.flush();
writer.close();
}
catch (IOException e) { e.printStackTrace(); return false; }
}
}
Unlike the other answer, here the downloaded json string itself is saved in file. So Serialization is not necessary
Now loading the json from url can be done by calling
jsonLoad jtask=new jsonLoad ();
jtask.doInBackground("http:www.json.com/urJsonFile.json");
this will save the contents to the file.
To open the saved json string
File file = new File(getApplicationContext().getFilesDir(),"nowList.cache");
StringBuilder text = new StringBuilder();
try {
BufferedReader br = new BufferedReader(new FileReader(file));
String line;
while ((line = br.readLine()) != null) {
text.append(line);
text.append('\n');
}
br.close();
}
catch (IOException e) {
//print log
}
JSONObject jsonObject = new JSONObject(text);