OOM on devices with smaller RAM - android

I have two json files in the assets folder. The problem is that on devices with smaller memory I get the out of memory error. What can I do to solve this? I have the following code:
Variables to store json
private static JSONObject one;
private static JSONObject two;
Method to set variables
public static void setJSON(Context context){
try {
one = new JSONObject(loadJSON(context,"one.json"));
two = new JSONObject(loadJSON(context,"two.json"));
} catch (JSONException e) {
e.printStackTrace();
}
}
Method to load json
private static String loadJSON(Context context, String filename){
try {
InputStream is = context.getAssets().open(filename);
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
String json = new String(buffer, "UTF-8");
return json;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}

There are a couple of ideas which might help here (and it would have helped to show a JSON file snippet)
A) How big are your JSON files? JSON processing is memory heavy, as you need to have RAM for the parser and the objects it creates in memory. Can you shrink the JSONs?
B) Can you load them one at a time? process, and free?
C) If all else fails, try splitting them into bunches of several objects, then load.
D) All in all, JSON is a terrible form of serialization. If you can use Java serialization instead, you'll be looking at a LOT less memory.

Do not use JSON, but convert your data to normal SQLite database and have it prepopulated in your APK file in assets folder. Then on first run you install it to app folder (you can use this tool) and then, finally use normal database and just get data you need at that moment, without need of loading whole JSON

Related

How to access lottie files outside res folder programatically

I don't know this is a duplicate question or not, but i tried to search similar question according to this.
I want to access the file that located outside /res folder programatically.
I already know if we want to access /res folder, then we just call it's id like getString(), getDrawable() etc.
But in my case, I want to access anim_empty.json programatically. How to do that?
Try following method for accessing JSON data:
public static String loadJSONFromAsset(Context mContext, String fileName) {
String json;
try {
InputStream is = mContext.getAssets().open(fileName);
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;
}
Modify the method according to your usage..
In the truth, i just wanted to call the Lottie animation files, i thought that i need to write script like the answer above but all i need is just these (Getting Started With Animations in Android Using Lottie — Kotlin and enter link description here):
lottieAnimationView = findViewById(R.id.empty_hstanim);
lottieAnimationView.setAnimation("anim_empty.json");
lottieAnimationView.playAnimation();
Thanks for the kind answer anyway!

Saving ImageView via GSON for SharedPreferences?

I want to save an object(of type MyObject) in Shared Preference via gson:
PS: store and retrieve a class object in shared preference
So 1 of the fields in MyObject is an ImageView which is fetched from a url.
Now when I do:
String json = gson.toJson(myObject);
I get a stackoverflow error. When I comment out the ImageView from my MyObject POJO this error gets resolved.
Q1- There are barely 8-10 images. So how do I store them through gson??
Q2- And is it a good practise to store images through gson, if not so then what better option do I have?
I think the error comes due to converting ImageView to string.
You store data that can be converted to string or numbers (long, int ...) in gson/sharedpreferences.
you can't and you shouldn't store ImageView because it is a UI object that is meant to be used to display Images in android layout.
With that being said, try saving your actual Image to a private directory that belongs to your app instead of this.
try {
Bitmap bmp = yourImageView.getDrawingCache();
FileOutputStream out = new FileOutputStream(pathToOutputFile);
bmp.compress(Bitmap.CompressFormat.PNG, 100, out);
out.close();
} catch (Exception e) {
e.printStackTrace();
}
For more about storage in android : Storage Guide

How can I store a non-string object in data memory?

In particular, I want to store a given gesture in the device's memory. Usually for these things I use SharedPreferences, but since gesture isn't a primitive data type, that doesn't work here; I also looked into storing it on Internal Storage, which is what I want, but the code here: http://developer.android.com/guide/topics/data/data-storage.html suggests this only works for strings.
Is there a way to easily store objects in the device memory, or do I need to convert the object to a string then back convert when I read the file?
Gesture mGesture;
SharedPreferences stored = getSharedPreferences("Shared Preferences", 0);
SharedPreferences.Editor editor = stored.edit();
byte[] storedGesture = serializeObject(mGesture);
String storedGestureString = new String(storedGesture);
editor.putString("Gesture Password", storedGestureString);
}
public static byte[] serializeObject(Object mObject){
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try{
ObjectOutput out = new ObjectOutputStream(bos);
out.writeObject(mObject);
out.close();
byte[] buf = bos.toByteArray();
return buf;
} catch (IOException ioe) {
Log.e("serialize object", "error", ioe);
return null;
}
}
There's the relevant code to my attempt at serializing, the app crashes when I hit the Confirm button after creating the gesture. The Confirm button runs this code, basically.
I think you can serialize the object and back. That way you'll be able to use it both with SharedPreferences and Internal Storage.
Here is a tutorial on how to implement Serialization in Java (as well as Android) -
http://www.tutorialspoint.com/java/java_serialization.htm
Look into Java's Serializable interface. You can make your own object that implements Serializable to hole the gesture, then write that object to internal storage. Here is a link for using serialization in Android.

How do you save and load mixed data types?

I have couple of dozen pieces of data that I need to save and load on start of the application. They are int, String, long , array data types. I am confused that there seems to be so many ways to do this. It seems each variation has different methods. The some of the data gets modified while the app runs. Lets say I have the following
int WifiOn="1";
private long Lasttime="00/00/00";
private String UserId="12345678";
private String URLResource[]= {"A","B","C");
//I open file...
FileOutputStream fos = openFileOutput("userPref.dat", Context.MODE_PRIVATE);
what do I do next with my four data types to save them out to internal storage?
And then what is the method to load them?
Apart from the SharedPreferences and SQLite databases that Dheeresh Singh mentions you can also use Serialization since you only use simple datatypes.
How to write data to a file with serialization:
//create an ObjectOutputStream around your (file) OutputStream
ObjectOutputStream oos = new ObjectOutputStream(fos);
//The OOS has methods like writeFloat(), writeInt() etc.
oos.writeInt(myInt);
oos.writeInt(myOtherInt);
//You can also write objects that implements Serializable:
oos.writeObject(myIntArray);
//Finally close the stream:
oos.flush();
oos.close();
How to read data from a file with serialization:
//Create an ObjectInputStream around your (file) InputStream
ObjectInputStream ois = new ObjectInputStream(fis);
//This stream has read-methods corresponding to the write-methods in the OOS, the objects are read in the order they were written:
myInt = ois.readInt();
myOtherInt = ois.readInt();
//The readObject() returns an Object, but you know it is the same type that you wrote, so just cast it and ignore any warnings:
myIntArray = (int[]) ois.readObject();
//As always, close the stream:
ois.close();
On a side note, consider wrapping your In/OutStream in a BufferedInput/OutputStream to squeeze out some extra read/write performance.
id data is limited then can use shared preference and if data is much can use SQLite database
dozen pieces of data
Better to use SQLite database which is easy and efficient also for your need
see link for how to use that
as per http://developer.android.com/guide/topics/data/data-storage.html
Your data storage options are the following:
Shared Preferences
Store private primitive data in key-value pairs.
Internal Storage
Store private data on the device memory.
External Storage
Store public data on the shared external storage.
SQLite Databases
Store structured data in a private database.
Network Connection
Store data on the web with your own network server.
if all the data is formatted the exact same way, you should probably use JSON, in a function you can create the objects and then write them into your file.
public bool writeToFile(int wifiOn, long lastTime, String userId, String [] urlResources) {
JSONObject toStore = new JSONObject();
FileOutputStream fos = openFileOutput("userPref.dat", Context.MODE_PRIVATE);
toStore.put("wifiOn", wifiOn);
toStore.put("lastTime", lastTime);
toStore.put("userId", userId);
toStore.put("urlResources", urlResources);
try {
fos.write(toStore.toString().getBytes());
fos.close();
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}

Better file serialization way for proper cpu usage?

I use following file serialization method to retrieve my data from disk.
public Vector load(String fileName) {
try {
FileInputStream fis = openFileInput(fileName);
ObjectInputStream in = new ObjectInputStream(fis);
Vector obj = (Vector) in.readObject();
in.close();
return obj;
} catch (Exception e) {
Log.e(TAG, e.toString());
}
return null;
}
I have 35K sized file to be serialized. It works perfect but thread uses cpu violently and causes slow application to use. I load this file just once.
Is there any better way for serialization or is there any different way to handle usage cpu of thread ?
You can also consider using Parcel for serialization, it's much more lightweight type of storage.
http://developer.android.com/reference/android/os/Parcelable.html
Don't use Vector, use ArrayList - there won't be any synchronization overhead.
If your operation is going long, just show a ProgressDialog within AsyncTask, like here.

Categories

Resources