How to append items to JSON file without parsing and rewriting - android

I am generating Observation objects and want to add them to a json file. The way I'm doing it now, I'm parsing existing file and converting it to JSON object, then adding a new Observation instance to the retrieved collection, parsing it back to JSON and re-writing the file.
Here's my code:
final File file = getFile();
final ObservationSet observationSet = retrievePreviousObservations(file);
observationSet.getObservations().add(observation[0]);
final OutputStream os = new FileOutputStream(file);
os.write(GsonHelper.toJson(observationSet).getBytes());
os.close();
...
private ObservationSet retrievePreviousObservations(final File file) {
ObservationSet observationSet = new ObservationSet();
try {
final BufferedReader br = new BufferedReader(new FileReader(file));
observationSet = GsonHelper.getGson().fromJson(br, ObservationSet.class);
} catch (FileNotFoundException e) {
Log.w(TAG, "No previous file found, this is the first entry", e);
}
return observationSet;
}
The problem is, that the Observation objects are quite big and after several tens of entries, this appending process takes really long time (generally more than 10 seconds for 20+ items in the collection).
Is there a way to append to existing JSON file without having to parse the existing one, adding the object, parsing it back and rewriting the file?

Related

Most optimal way to load large JSON into a List<>

I am working on android multiplayer game. My JSON file contains 800 000+ dictionary words. JSON array is being loaded in List once players enter GameActivity to actually play game. So each time player starts 1vs1 game, JSON is being loaded into a List<>.
Now, I have 2 options:
Load JSON the most optimal way so user does not get out of memory error after a while
Load JSON file into a List<> only once, when application is open.
I'm not sure about any of these 2 cases, can someone give me a hand on how to do this please? Thank you
I can't comment because of my repu.
But you can try to few different approaches into this problem.
If your JSON changes very rarely i can suggest this method.
You can put your json inside your asset file. and call in runtime with this
public String loadJSONFromAsset() {
String json = null;
try {
InputStream is = getActivity().getAssets().open("yourfilename.json");
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
json = new String(buffer, "UTF-8");
} catch (IOException ex) {
ex.printStackTrace();
return null;
}
return json;
}
Or you can fetch your Json before app starts and store in ContentProvider (DB or SharedPreference). And this way you only fetch your json when it is necessary.
//right before fetching JSON
boolean thereIsAnyUpdatesInJSON = checkYourDictionaryJsonIfThereAreAnyUpdates();
if(!isDictionaryDatabaseAvailable && thereIsAnyUpdatesInJSON){
fetchYourDictJson();
}

Reading data from a json file BufferedReader returns only null

I'm currently learning android with a books called "Android Programming - The Big Nerd Ranch Guide".
As a part of a learning project we create Json serializer for saving and loading data. Writing the file appearently works fine, and I get no error messages on the Logcat. After I terminate the app and recreate it, the data loader is called and raises the following exception:
org.json.JSONException: End of input at character 0
I've looked for this issue online and figured it's probably because the BufferedReader returns an empty response. I've checked and indeed it is the case.
For simplicity sake, I've temporarily put a BufferedReader into the saving function and tried reading the info I've just saved into the file, and still the BufferedReader returns only null.
public void saveCrimes(ArrayList<Crime>crimes)
throws JSONException, IOException {
JSONArray array = new JSONArray();
for(Crime c: crimes)
array.put(c.toJSON());
Writer writer = null;
try {
OutputStream out = mContext.openFileOutput(mFileName, Context.MODE_PRIVATE);
writer = new OutputStreamWriter(out);
writer.write(array.toString());
Log.d(TAG, array.toString());
} finally {
if(writer == null)
writer.close();
}
// Extracting the data
BufferedReader bufferedReader = null;
try {
InputStream inputStream = mContext.openFileInput(mFileName);
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
if (bufferedReader.readLine() == null)
Log.d(TAG, "WHY GOD WHYYYYYYY");
}catch (IOException e){
}
}
(The two log messages from the code, the first one displays the data that is in the JsonArray I'm using)
D/CriminalIntentJSONSerializer: [{"date":"Mon May 14 17:33:08 GMT+00:00 2018","id":"97fe9532-991f-4352-9de1-602fa8dfa93e","isSolved":true,"title":""}]
D/CriminalIntentJSONSerializer: WHY GOD WHYYYYYYY
Would love to hear your insight.
BufferedReader bufferedReader = null;
try {
InputStream inputStream = mContext.openFileInput(mFileName);
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
if (bufferedReader.readLine() == null)
Log.d(TAG, "WHY GOD WHYYYYYYY");
}catch (IOException e){
}
Ok. you've created your BufferedReader bufferedReader = null;
What happens when yuou say bufferedReader = new BufferedReader(anything)...Well...it can't call a new instance the same thing that's already been declared...in fact, it's already been instantiated as null. So you can't create a new instance of the same name.
Try deleting the line where you point it at null. Then, substitute
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
for the original declaration in your try block
Try to check if mFilename is empty on second try-catch, usually in Android instance disappear easily.
PD: I advise you choice another JSON library to manipulte JSON files, they are lightweight and easy-to-use.
== Edit ==
Have you added writing and reading permissions on AndroidManifest?
If answer is "there it is" try to debug app step-by-step looking for variables and in-variables for checking existence of values.
Could be file isn't writing itself or it's writing empty.
Error basically is empty string or non-format JSON-like:
""
"[{"a": "abdc", "b": "jef2","
Paying attention to BufferedReader because it read lines each and you need all file and then join into string variable.
Also, try to use android file explorer that come in AndroidStudio. There you can explore files, logs and database files and export them to your specific folders (Documents, Downloads, etc). Generally files written by app are stored in data -> <com.your.app.package>.

Android device incomplete JSON?

From my Android application I write a JSON string to a JSON-file located on an Android tablet in /sdcard/subdirectory, in the onStop()-method. This function executes succesfully.
If I copy this resulting .json-file from the Android device to my computer and I open this JSON-file in Notepad++, the JSON is not valid: it is incomplete.
This is the content of said JSON-file:
{... there are about 20 of these elements, I won't list them all for readability...},
{"name":"Marker7","long":2.924128,"lat":51.204594,"warning":"Sharp turn"},
{"name":"Marker8","long":2.9260479999999998,"lat":51.203364,"warning":"Dead end"},
{"name":"Marker9","long":2.926252,"lat":51.203209,"warning":"
As you can see, the JSON is cut off at the warning part of Marker9, making this invalid JSON.
What is weird is the following: my application also reads from this file in the onCreate()-method, and if I print this JSON, it does show the correct and complete JSON! So within my Android app I don't experience any issues, and I assume my writing method and the resulting JSON-file is working as intended since the correct data is retrieved from the reading-function. However if I want to copy this JSON and use it elsewhere I won't have a valid JSON-file.
Why is this? Does this have something to do with the ext4-filesystem that my Android device is using?
I also noticed that this seems to happen when the file reaches the 1.18kB size mark (as shown in my explorer view, but again: the correct and complete IS retrieved within the Android app...), because each time I copy the file and it appears to be cut off, the size is always exactly 1.18kB.
Update
The code for reading the JSON:
public String loadJSON() {
String json = null;
try {
//InputStream is = getAssets().open("markers.json");
File jsonFile = new File(Environment.getExternalStorageDirectory(), "osmdroid/markers.json");
FileInputStream is = new FileInputStream(jsonFile);
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
json = new String(buffer, "UTF-8");
} catch (IOException ex) {
ex.printStackTrace();
return null;
}
return json;
}
private void readJsonMarkers() throws JSONException {
JSONObject obj = new JSONObject(loadJSON());
JSONArray jsonArray = obj.getJSONArray("markers");
System.out.println("JSON LOAD: " + jsonArray); // this shows the correct, full list of markers
}
The code for writing the JSON:
private void writeJsonMarkers() throws JSONException {
JSONArray data = new JSONArray();
for(OverlayItem oi: waypointMarkers){
JSONObject obj = new JSONObject();
try {
obj.put("name", oi.getTitle());
obj.put("long", oi.getPoint().getLongitude());
obj.put("lat", oi.getPoint().getLatitude());
obj.put("warning", oi.getSnippet());
data.put(obj);
} catch (JSONException e) {
e.printStackTrace();
}
}
JSONObject rootObj = new JSONObject(loadJSON());
rootObj.remove("markers");
rootObj.put("markers",data);
// this method is used to remove the existing markers-list from the JSON, and add an updated markers-list to it
File jsonFile = new File(Environment.getExternalStorageDirectory(), "osmdroid/markers.json");
try {
FileWriter jsonWriter = new FileWriter(jsonFile);
jsonWriter.write(rootObj.toString());
jsonWriter.flush();
jsonWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}

How to download json file and store localy in the device to use it as source for different listviews?

I am using an application which parse remote json into a list view and it works fine as single activity and if the device is online..
Is there a way to download the json data locally(cached) in the device and then pull it inside my app inside Listviews.. i am planning to have multiple listviews which takes the data from the same json file and then filter them out based on some criteria such as location then allow user to swipe the app for different views.
I appreciate your advices,
Abdul
I have one idea , i hope it will work for you
Store content of file in Object that is in cache in form of JSON .
Now Object have all your content which you can pass to JsonArray or JsonObject to parse.
File file = new File("C:/ciphertext.txt");
int ch;
StringBuffer strContent = new StringBuffer("");
FileInputStream fin = null;
try {
fin = new FileInputStream(file);
while ((ch = fin.read()) != -1)
strContent.append((char) ch);
fin.close();
} catch (Exception e) {
System.out.println(e);
}
Now our strContent have content of file.
You can store the data in SharedPreference.
Check this out
And also, there are more Storage Options for you.

ANDROID: JSONArray save in Internal Storage to work without internet conection

I have a PHP JSON that sends me JSONArray.
public JSONArray lastTweet()throws ClientProtocolException,IOException,JSONException{
StringBuilder url = new StringBuilder(URL);
HttpGet get = new HttpGet(url.toString());
HttpResponse r = client.execute(get);
int status = r.getStatusLine().getStatusCode();
if(status == 200){
HttpEntity e = r.getEntity();
String data = EntityUtils.toString(e);
JSONArray timeline = new JSONArray(data);
return timeline;
}
return null;
}
I can get Object and values from this JSONArray (timeline), but it work only then application have internet conection. I want to save this JSON in my internal storage like a json file and after work with this file in offline mod. How i can do this?
Try using JSON Simple library which allows easy encoding/decoding of JSON files.
Examples: Encoding
Then it's just plain:
try {
outStream = openFileOutput("tweet.json", Context.MODE_PRIVATE);
outStream.write(json.getJSONString().getBytes());
outStream.close();
} catch (Exception e) {
e.printStackTrace();
}
However if you do not want to store it for forever, or for re-sending purposes, I recommend using Cache
Mind that cache can be automatically wiped, so it's up to you. More on this, as always, on the Android developers site: Android: Saving Files # Write Internal Storage
UPDATE:
Turns out that android JSONObject.toString() produces coherent JSON output that can be saved to a file the way desciber above, without any 3rd party library, however you would need to marshall it back to JSONObject/Array/Primitive by yourself, and that will take some extra work.

Categories

Resources