I'm downloading lot of images from Internet and storing into a hashmap and showing in a ListView. I want to cache the images. For that, I am storing the Hashmap object into a file inside onDestroy() of my activity and getting back the object inside oncreate().
Map<String, Drawable> hashmap; //storing the urls of images and downloaded image `Drawables` into this map
Inside onCreate():
File f = new File(Environment.getExternalStorageDirectory()+"/image_cache.ser");
if(f.exists()){
FileInputStream fin = new FileInputStream(f);
ObjectInputStream ois = new ObjectInputStream(fin);
hashmap = (HashMap<String, Drawable>)ois.readObject();
ois.close();
Here creating a custom adapter and showing the hashmap drawable images in a listview
}
Inside onDestroy()
#Override
protected void onDestroy() {
super.onDestroy();
File f = new File(Environment.getExternalStorageDirectory()+"/image_cache.ser");
try {
if(hashmap != null && hashmap.size() >= 1){
FileOutputStream fout = new FileOutputStream(f);
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject(hashmap);
oos.flush();
oos.close();
}
} catch (Exception e) {
e.printStackTrace();
f.delete();
}
}
Problem : Getting this exception:
java.io.NotSerializableException android.graphics.drawable.BitmapDrawable inside ondestoy().
Why the hashmap object is not getting serialized ? Where i am going wrong. Could you please put me in a correct way if I'm wrong to cache images?
you can not write your hashmap because the class Drawable is not Serializable
Drawable does not implement Serializable
It just won't work this way. The errors says, that you are trying to serialize a Drawable, which is not implemented, since there are factories to do so in different ways. There is no simple solution with this hashmap.
Related
My application should work not only in online but also in offline mode. For that reason I am considering find the best way for cashing data. I't like use SharedPreference for store data but in android documentation writen Maximum size in characters allowed for a preferences value is 8192. I don't know this is ok or not? I tried to pass out of this idea trying to use FileCashing or sqLite cashing.
So what you think guys what is the best SharedPreference vs FileCashing or vs SqLiteCaching?
Save the json in cache directory as file....
Save:
// 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();
Retrieve:
// Load in an object
ObjectInputStream in = new ObjectInputStream(new FileInputStream(new File(new File(getCacheDir(),"")+"cacheFile.srl")));
JSONObject jsonObject = (JSONObject) in.readObject();
in.close();
I personally like to do this the following way. Create a SQLite database that can hold your content. Then, bind the user interface directly to the database using Adapters & Content Providers that send a notification whenever the data is changed so that the UI can update itself. The last piece in the equation is some form of synchronization service that downloads content and saves it to the database asynchronously. That way, you can manage your data very easily because it is all in the same place. The only part you'll have to figure out for your app is how you decide when to update or remove the data from the database.
Adapters
ContentProvider
Synchronization
Based on your requirement I would recommend SQLite data base.
Since shared preference is suitable for configuration storage - often small data/strings.
File cache is hard to manage, so I recommend SQLite - easy to manage and ability to store mass data.
Considering the performance, if the number of index is not that huge, SQLite database should have the acceptable performance. E.g. only several ms slower than a file cache.
You might be able to combine these two approaches together. Use random access file with index-offset stored in SQLite.
I have used Internal Storage which store file in Application package directory that can't be accessible by not rooted device.
Here the class which can create, read and delete the file
public class ReadWriteJsonFileUtils {
Activity activity;
Context context;
public ReadWriteJsonFileUtils(Context context) {
this.context = context;
}
public void createJsonFileData(String filename, String mJsonResponse) {
try {
File checkFile = new File(context.getApplicationInfo().dataDir + "/new_directory_name/");
if (!checkFile.exists()) {
checkFile.mkdir();
}
FileWriter file = new FileWriter(checkFile.getAbsolutePath() + "/" + filename);
file.write(mJsonResponse);
file.flush();
file.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public String readJsonFileData(String filename) {
try {
File f = new File(context.getApplicationInfo().dataDir + "/new_directory_name/" + filename);
if (!f.exists()) {
onNoResult();
return null;
}
FileInputStream is = new FileInputStream(f);
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
return new String(buffer);
} catch (IOException e) {
e.printStackTrace();
}
onNoResult();
return null;
}
public void deleteFile() {
File f = new File(context.getApplicationInfo().dataDir + "/new_directory_name/");
File[] files = f.listFiles();
for (File fInDir : files) {
fInDir.delete();
}
}
public void deleteFile(String fileName) {
File f = new File(context.getApplicationInfo().dataDir + "/new_directory_name/" + fileName);
if (f.exists()) {
f.delete();
}
}
}
You can create, read and delete the file by calling ReadWriteJsonFileUtils class methods as follows:
For creating file:
try {
new ReadWriteJsonFileUtils(context).createJsonFileData(file_name, data);
} catch (Exception e) {
e.printStackTrace();
}
For reading file:
String jsonString = new ReadWriteJsonFileUtils(context).readJsonFileData(file_name);
For deleting single file
new ReadWriteJsonFileUtils(context).deleteFile(file_name);
For deleting all file
new ReadWriteJsonFileUtils(context).deleteFile();
I am working on some way to store a GPS location within the internal file storage and retrieve it on demand in another method.
As I am new to Android I have tried out several ways and decided to go with the FileOutput-/InputStream as it is more comprehensible to me. I am working with the Android location API(http://developer.android.com/reference/android/location/Location.html).
I know that saving a location Object works technically via writing it to a string and later to bytes, but how can I load a saved file and have the saved location object returned?
My code approach:
public void saveCurrentLocation(){ //method works, I can see the saved file in the file explorer
Location currentLoc = gpsClass.getCurrentLocation(); //method within gpsClass that returns current location
try {
FileOutputStream fos = openFileOutput("SaveLoc", Context.MODE_PRIVATE);
fos.write(currentLoc.toString().getBytes());
fos.close();
}
catch(Exception e) { e.printStackTrace();}
}
public void loadSavedLocation() {
Location savedLoc;
try{
BufferedReader inputReader = new BufferedReader(new InputStreamReader(openFileInput("SaveLoc")));
String inputString;
StringBuffer stringBuffer = new StringBuffer();
while((inputString = inputReader.readLine()) != null) {
stringBuffer.append(inputString);
}
gpsClass.update(??);
}
catch(Exception e) {e.printStackTrace();}
}
I'd like to pass the location Object readout in inputString to "gpsClass.update()" which only takes variables of the type Location. Do I have to make the Object serializable and if yes, how?
Many thanks in advance!
Why not persist your location objects into a SQLite database?
Or something like this:
Save:
FileOutputStream fos = context.openFileOutput(fileName, Context.MODE_PRIVATE);
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(your object);
os.close();
Load:
FileInputStream fis = context.openFileInput(fileName);
ObjectInputStream is = new ObjectInputStream(fis);
YourClass yourObject = (YourClass) is.readObject();
is.close();
return yourObject;
This should get you back on track
My application should work not only in online but also in offline mode. For that reason I am considering find the best way for cashing data. I't like use SharedPreference for store data but in android documentation writen Maximum size in characters allowed for a preferences value is 8192. I don't know this is ok or not? I tried to pass out of this idea trying to use FileCashing or sqLite cashing.
So what you think guys what is the best SharedPreference vs FileCashing or vs SqLiteCaching?
Save the json in cache directory as file....
Save:
// 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();
Retrieve:
// Load in an object
ObjectInputStream in = new ObjectInputStream(new FileInputStream(new File(new File(getCacheDir(),"")+"cacheFile.srl")));
JSONObject jsonObject = (JSONObject) in.readObject();
in.close();
I personally like to do this the following way. Create a SQLite database that can hold your content. Then, bind the user interface directly to the database using Adapters & Content Providers that send a notification whenever the data is changed so that the UI can update itself. The last piece in the equation is some form of synchronization service that downloads content and saves it to the database asynchronously. That way, you can manage your data very easily because it is all in the same place. The only part you'll have to figure out for your app is how you decide when to update or remove the data from the database.
Adapters
ContentProvider
Synchronization
Based on your requirement I would recommend SQLite data base.
Since shared preference is suitable for configuration storage - often small data/strings.
File cache is hard to manage, so I recommend SQLite - easy to manage and ability to store mass data.
Considering the performance, if the number of index is not that huge, SQLite database should have the acceptable performance. E.g. only several ms slower than a file cache.
You might be able to combine these two approaches together. Use random access file with index-offset stored in SQLite.
I have used Internal Storage which store file in Application package directory that can't be accessible by not rooted device.
Here the class which can create, read and delete the file
public class ReadWriteJsonFileUtils {
Activity activity;
Context context;
public ReadWriteJsonFileUtils(Context context) {
this.context = context;
}
public void createJsonFileData(String filename, String mJsonResponse) {
try {
File checkFile = new File(context.getApplicationInfo().dataDir + "/new_directory_name/");
if (!checkFile.exists()) {
checkFile.mkdir();
}
FileWriter file = new FileWriter(checkFile.getAbsolutePath() + "/" + filename);
file.write(mJsonResponse);
file.flush();
file.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public String readJsonFileData(String filename) {
try {
File f = new File(context.getApplicationInfo().dataDir + "/new_directory_name/" + filename);
if (!f.exists()) {
onNoResult();
return null;
}
FileInputStream is = new FileInputStream(f);
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
return new String(buffer);
} catch (IOException e) {
e.printStackTrace();
}
onNoResult();
return null;
}
public void deleteFile() {
File f = new File(context.getApplicationInfo().dataDir + "/new_directory_name/");
File[] files = f.listFiles();
for (File fInDir : files) {
fInDir.delete();
}
}
public void deleteFile(String fileName) {
File f = new File(context.getApplicationInfo().dataDir + "/new_directory_name/" + fileName);
if (f.exists()) {
f.delete();
}
}
}
You can create, read and delete the file by calling ReadWriteJsonFileUtils class methods as follows:
For creating file:
try {
new ReadWriteJsonFileUtils(context).createJsonFileData(file_name, data);
} catch (Exception e) {
e.printStackTrace();
}
For reading file:
String jsonString = new ReadWriteJsonFileUtils(context).readJsonFileData(file_name);
For deleting single file
new ReadWriteJsonFileUtils(context).deleteFile(file_name);
For deleting all file
new ReadWriteJsonFileUtils(context).deleteFile();
I want to read/write data dictionary in file which is in android internal/external memory. In WP7, they have used IsolatedStorage for storing the dictionary directly. In IOS, they can write NSDictionary directly to the file. Please anyone tell me the way to write DataDictionary into file.
Note: I have the keys and values in the Map variable.
how to store this Map directly to file
I would suggest putting your words into a database for the following reasons
DB lookups on android with SQLite are "fast enough" (~1ms) for even
the most impatient of users
Reading large files into memory is a dangerous practice in
memory-limited environments such as android.
Trying to read entries out of a file "in place" rather than "in
memory" is effectively trying to solve all the problems that SQLite
already solves for you.
Embed a database in the .apk of a distributed application [Android]
You can find more detailed examples by searching object serialization
[EDIT 1]
Map map = new HashMap();
map.put("1",new Integer(1));
map.put("2",new Integer(2));
map.put("3",new Integer(3));
FileOutputStream fos = new FileOutputStream("map.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(map);
oos.close();
FileInputStream fis = new FileInputStream("map.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
Map anotherMap = (Map) ois.readObject();
ois.close();
System.out.println(anotherMap);
[EDIT 2]
try {
File file = new File(getFilesDir() + "/map.ser");
Map map = new HashMap();
map.put("1", new Integer(1));
map.put("2", new Integer(2));
map.put("3", new Integer(3));
Map anotherMap = null;
if (!file.exists()) {
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(map);
oos.close();
System.out.println("added");
} else {
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
anotherMap = (Map) ois.readObject();
ois.close();
System.out.println(anotherMap);
}
} catch (Exception e) {
}
[EDIT 3]
Iterator myVeryOwnIterator = meMap.keySet().iterator();
while(myVeryOwnIterator.hasNext()) {
String key=(String)myVeryOwnIterator.next();
String value=(String)meMap.get(key);
// check for value
}
I'm unsure if using SharedPreferences (link) is something that is suitable for your usecase.
You store via a key-value pair, and can have multiple SharedPreferences per application. While both are stored as String objects, the value can be automatically cast to other primitives using built in methods.
Mark Murphy has written a library, cwac-loaderex (link), to facilitate access of SharedPreferences via the use of the Loader pattern (link), which offsets some of the work you need to do to keep IO off the main thread.
Hi in my application I am saving string information entered by the user. then serializing those string for retrival later. When I go to open the file to where they are saved I always only get the last string that was entered. Can you see where i am going wrong?
This is the retrival code
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.lightlist);
adapter = new ArrayAdapter<String>(LightList.this, android.R.layout.simple_list_item_1, lightNames);
refreshBut = (Button)findViewById(R.id.button1);
try {
File file = getCacheDir();
fis = new FileInputStream(new File(file, LightSetup.FILENAME ));
ois = new ObjectInputStream(fis);
String a;
while((a = (String)ois.readObject()) != null){
adapter.add(a);
setListAdapter(adapter);
}
ois.close();
} catch (FileNotFoundException e) {e.printStackTrace();} catch (StreamCorruptedException e){e.printStackTrace();
} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}
}//end onCreate
And this is the serializing code
public void onClick(View arg0) {
String stringData = data.getText().toString();
try {
File file = getCacheDir();
fos = new FileOutputStream(new File(file,FILENAME ));
os = new ObjectOutputStream(fos);
os.writeObject(stringData);
fos.close();
os.close();
} catch (IOException e) {e.printStackTrace();}
Intent i = new Intent("com.Sonny.HCIProject.CreateConfirm");
startActivity(i);
finish();
}//end onClick
You are doing 2 things in a wrong way:
You don't do setListAdapter in a loop, though it might not do you any harm, you don't need to.
The code in your onClick method does not do what you expect, it simply overwrites the data you serialized in the last time. You need to re-construct the objects you serialized in the past using ObjectInputStream and then add your current object to the object graph(I think you need a List), then you can safely serialize all your objects in the file without overwriting your old objects.
Even you can serialize objects like that, I recommend you store your data in SQLite database in stead of using Java serialization, reconstructing a whole lot of unrelated objects just to store another object is overkill. With SQLite, you INSERT a record to the database, and then you can SELECT all records from the database, it is fast and your code will be more succinct.