How to serialize a Bundle? - android

I'd like to serialize a Bundle object, but can't seem to find a simple way of doing it. Using Parcel doesn't seem like an option, since I want to store the serialized data to file.
Any ideas on ways to do this?
The reason I want this is to save and restore the state of my activity, also when it's killed by the user. I already create a Bundle with the state I want to save in onSaveInstanceState. But android only keeps this Bundle when the activity is killed by the SYSTEM. When the user kills the activity, I need to store it myself. Hence i'd like to serialize and store it to file. Of course, if you have any other way of accomplishing the same thing, i'd be thankful for that too.
Edit:
I decided to encode my state as a JSONObject instead of a Bundle. The JSON object can then be put in a Bundle as a Serializable, or stored to file. Probably not the most efficient way, but it's simple, and it seems to work ok.

storing any Parcelable to a file is very easy:
FileOutputStream fos = context.openFileOutput(localFilename, Context.MODE_PRIVATE);
Parcel p = Parcel.obtain(); // i make an empty one here, but you can use yours
fos.write(p.marshall());
fos.flush();
fos.close();
enjoy!

I use SharedPreferences to get around that limitation, it uses the same putXXX() and getXXX() style of storing and retrieving data as the Bundle class does and is relatively simple to implement if you have used a Bundle before.
So in onCreate I have a check like this
if(savedInstanceState != null)
{
loadGameDataFromSavedInstanceState(savedInstanceState);
}
else
{
loadGameDataFromSharedPreferences(getPreferences(MODE_PRIVATE));
}
I save my game data to a Bundle in onSaveInstanceState(), and load data from a Bundle in onRestoreInstanceState()
AND
I also save game data to SharedPreferences in onPause(), and load data from SharedPreferences in onResume()
onPause()
{
// get a SharedPreferences editor for storing game data to
SharedPreferences.Editor mySharedPreferences = getPreferences(MODE_PRIVATE).edit();
// call a function to actually store the game data
saveGameDataToSharedPreferences(mySharedPreferences);
// make sure you call mySharedPreferences.commit() at the end of your function
}
onResume()
{
loadGameDataFromSharedPreferences(getPreferences(MODE_PRIVATE));
}
I wouldn't be surprised if some people feel this is an incorrect use of SharedPreferences, but it gets the job done. I have been using this method in all my games (nearly 2 million downloads) for over a year and it works.

Convert it to SharedPreferences:
private void saveToPreferences(Bundle in) {
Parcel parcel = Parcel.obtain();
String serialized = null;
try {
in.writeToParcel(parcel, 0);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
IOUtils.write(parcel.marshall(), bos);
serialized = Base64.encodeToString(bos.toByteArray(), 0);
} catch (IOException e) {
Log.e(getClass().getSimpleName(), e.toString(), e);
} finally {
parcel.recycle();
}
if (serialized != null) {
SharedPreferences settings = getSharedPreferences(PREFS, 0);
Editor editor = settings.edit();
editor.putString("parcel", serialized);
editor.commit();
}
}
private Bundle restoreFromPreferences() {
Bundle bundle = null;
SharedPreferences settings = getSharedPreferences(PREFS, 0);
String serialized = settings.getString("parcel", null);
if (serialized != null) {
Parcel parcel = Parcel.obtain();
try {
byte[] data = Base64.decode(serialized, 0);
parcel.unmarshall(data, 0, data.length);
parcel.setDataPosition(0);
bundle = parcel.readBundle();
} finally {
parcel.recycle();
}
}
return bundle;
}

In case you want to store it in persistent storage you can't rely on parcelable nor serializable mechanism. You have to do it by yourself and below is the way how I usually do it:
private static final Gson sGson = new GsonBuilder().create();
private static final String CHARSET = "UTF-8";
// taken from http://www.javacamp.org/javaI/primitiveTypes.html
private static final int BOOLEAN_LEN = 1;
private static final int INTEGER_LEN = 4;
private static final int DOUBLE_LEN = 8;
public static byte[] serializeBundle(Bundle bundle) {
try {
List<SerializedItem> list = new ArrayList<>();
if (bundle != null) {
Set<String> keys = bundle.keySet();
for (String key : keys) {
Object value = bundle.get(key);
if (value == null) continue;
SerializedItem bis = new SerializedItem();
bis.setClassName(value.getClass().getCanonicalName());
bis.setKey(key);
if (value instanceof String)
bis.setValue(((String) value).getBytes(CHARSET));
else if (value instanceof SpannableString) {
String str = Html.toHtml((Spanned) value);
bis.setValue(str.getBytes(CHARSET));
} else if (value.getClass().isAssignableFrom(Integer.class)) {
ByteBuffer b = ByteBuffer.allocate(INTEGER_LEN);
b.putInt((Integer) value);
bis.setValue(b.array());
} else if (value.getClass().isAssignableFrom(Double.class)) {
ByteBuffer b = ByteBuffer.allocate(DOUBLE_LEN);
b.putDouble((Double) value);
bis.setValue(b.array());
} else if (value.getClass().isAssignableFrom(Boolean.class)) {
ByteBuffer b = ByteBuffer.allocate(INTEGER_LEN);
boolean v = (boolean) value;
b.putInt(v ? 1 : 0);
bis.setValue(b.array());
} else
continue; // we do nothing in this case since there is amazing amount of stuff you can put into bundle but if you want something specific you can still add it
// throw new IllegalStateException("Unable to serialize class + " + value.getClass().getCanonicalName());
list.add(bis);
}
return sGson.toJson(list).getBytes(CHARSET);
}
} catch (Exception e) {
e.printStackTrace();
}
throw new IllegalStateException("Unable to serialize " + bundle);
}
public static Bundle deserializeBundle(byte[] toDeserialize) {
try {
Bundle bundle = new Bundle();
if (toDeserialize != null) {
SerializedItem[] bundleItems = new Gson().fromJson(new String(toDeserialize, CHARSET), SerializedItem[].class);
for (SerializedItem bis : bundleItems) {
if (String.class.getCanonicalName().equals(bis.getClassName()))
bundle.putString(bis.getKey(), new String(bis.getValue()));
else if (Integer.class.getCanonicalName().equals(bis.getClassName()))
bundle.putInt(bis.getKey(), ByteBuffer.wrap(bis.getValue()).getInt());
else if (Double.class.getCanonicalName().equals(bis.getClassName()))
bundle.putDouble(bis.getKey(), ByteBuffer.wrap(bis.getValue()).getDouble());
else if (Boolean.class.getCanonicalName().equals(bis.getClassName())) {
int v = ByteBuffer.wrap(bis.getValue()).getInt();
bundle.putBoolean(bis.getKey(), v == 1);
} else
throw new IllegalStateException("Unable to deserialize class " + bis.getClassName());
}
}
return bundle;
} catch (Exception e) {
e.printStackTrace();
}
throw new IllegalStateException("Unable to deserialize " + Arrays.toString(toDeserialize));
}
You represent data as byte array which you can easily store to file, send via network or store to sql database using ormLite as follows:
#DatabaseField(dataType = DataType.BYTE_ARRAY)
private byte[] mRawBundle;
and SerializedItem:
public class SerializedItem {
private String mClassName;
private String mKey;
private byte[] mValue;
// + getters and setters
}
PS: the code above is dependent on Gson library (which is pretty common, just to let you know).

Related

Solution to ArrayIndexOutOfBoundsException when restoring RecyclerView state with ArrayList of custom objects and Gson

I have a RecyclerView in which the views/data in the ViewHolders (image, title, description) are retrieved with the getter methods of a custom object Challenge.
I also have an ArrayList of type Challenge (ArrayList<Challenge> mChallenges) where I add all the challenges and I later pass this ArrayList as a parameter of my RecyclerView.Adapter subclass when I initialize it.
The ViewHolders of my RecyclerView also have a checkbox so users can select the challenges they want, and these chosen challenges are saved on a different ArrayList<Challenge> named currentSelectedChallenges. This is how they get added.
#Override
public void onChallengeChecked(int position) { // method of interface
if (!currentSelectedChallenges.contains(mChallenges.get(position))){
currentSelectedChallenges.add(mChallenges.get(position));
}
}
When the user leaves the fragment where the RecyclerView is contained, either with the back button or closing the app, I save the selected challenges ArrayList<Challenge> currentSelectedChallenges with a SharedPreferences using Gson like this:
#Override
public void onPause() {
super.onPause();
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
SharedPreferences.Editor editor = sharedPreferences.edit();
Gson gson = new Gson();
Type type = new TypeToken<ArrayList<Challenge>>(){}.getType();
String json = gson.toJson(currentSelectedChallenges, type);
editor.putString("selected challenges", json);
editor.apply();
}
And I restore currentSelectedChallenges on the onRestore method of the fragment in the following way:
#Override
public void onResume() {
super.onResume();
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
Gson gson = new Gson();
String json = sharedPreferences.getString("selected challenges", null);
Type type = new TypeToken<ArrayList<Challenge>>() {
}.getType();
currentSelectedChallenges = gson.fromJson(json, type);
if (currentSelectedChallenges == null) {
currentSelectedChallenges = new ArrayList<>();
} else
{
for (int i = 0; i < currentSelectedChallenges.size(); i++) {
int index = mChallenges.indexOf(currentSelectedChallenges.get(i));
mChallenges.get(index).setChecked(true);
}
mChallengesAdapter.notifyDataSetChanged();
}
}
When I try to restore the checked state of the CheckBox in the ViewHolder I get an ArrayIndexOutOfBoundsExceptions because currentSelectedChallenges.get(i) is not found inside mChallenges, so it returns -1. I have logged the challenges and the objects have different ids even though I can use the setter methods and will retrieve the same data.
I tried to trick Android and used this:
for (int i=0; i < currentSelectedChallenges.size(); i++) {
for (Challenge challenge : mChallenges) {
if (challenge.getName().equals(currentSelectedChallenges.get(i).getName())){
challenge.setChecked(true);
}
}
mChallengesAdapter.notifyDataSetChanged();
And it does tick in the UI the challenges that were checked by the user but then when I click again on the CheckBox it doesn't detect my click, so I know this is not the proper solution.
Could anyone explain how should I tackle this correctly?
mChallenges.indexOf(currentSelectedChallenges.get(i))
returns -1 because it compares reference instead of your interested data.
you should override equals and hashCode of Challenge class:
class Challenge{
// your current code
#Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof Challenge)) {
return false;
}
Challenge challenge = (Challenge) o;
return challenge.name.equals(name) /*&& compare other values for equality*/;
// also check for null name if it is necessary
}
#Override
public int hashCode() {
int result = 17;
result = 31 * result + name.hashCode();
//result = 31 * result + age; // other property
//result = 31 * result + passport.hashCode();// other property
return result;
}
}

Activity restarted when i press home button in android

I am afraid that my activity is restarted when i open it through TaskManager....
and my DefaultHttpClient object treated as fresh one..so here i am loosing the
session.
I tried by overriding the onSaveInstanceState() method..but no use..
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState); // the UI component values are saved here.
}
How i can get rid of this one...
when you press button Home, activity will pause and resume when reopen.
you shout put code to onCreate().
see activity lifecryde:
You could subclass Android Applications: You can init the HttpClient there and hold the reference.
Look here
Than you can access from activity your Application object with activity.getApplication()
If your session works with cookies than you may need a persistent cookie storeage (like database or shared preferences):
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import org.apache.http.client.CookieStore;
import org.apache.http.cookie.Cookie;
import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils;
/**
* A persistent cookie store which implements the Apache HttpClient
* {#link CookieStore} interface. Cookies are stored and will persist on the
* user's device between application sessions since they are serialized and
* stored in {#link SharedPreferences}.
* <p>
*/
public class PersistentCookieStore implements CookieStore {
private static final String COOKIE_PREFS = "CookiePrefsFile";
private static final String COOKIE_NAME_STORE = "names";
private static final String COOKIE_NAME_PREFIX = "cookie_";
private final ConcurrentHashMap<String, Cookie> cookies;
private final SharedPreferences cookiePrefs;
/**
* Construct a persistent cookie store.
*/
public PersistentCookieStore(Context context) {
cookiePrefs = context.getSharedPreferences(COOKIE_PREFS, 0);
cookies = new ConcurrentHashMap<String, Cookie>();
// Load any previously stored cookies into the store
String storedCookieNames = cookiePrefs.getString(COOKIE_NAME_STORE,
null);
if (storedCookieNames != null) {
String[] cookieNames = TextUtils.split(storedCookieNames, ",");
for (String name : cookieNames) {
String encodedCookie = cookiePrefs.getString(COOKIE_NAME_PREFIX
+ name, null);
if (encodedCookie != null) {
Cookie decodedCookie = decodeCookie(encodedCookie);
if (decodedCookie != null) {
cookies.put(name, decodedCookie);
}
}
}
// Clear out expired cookies
clearExpired(new Date());
}
}
#Override
public synchronized void addCookie(Cookie cookie) {
String name = cookie.getName() + cookie.getDomain();
// Save cookie into local store, or remove if expired
if (!cookie.isExpired(new Date())) {
cookies.put(name, cookie);
} else {
cookies.remove(name);
}
// Save cookie into persistent store
SharedPreferences.Editor prefsWriter = cookiePrefs.edit();
prefsWriter.putString(COOKIE_NAME_STORE,
TextUtils.join(",", cookies.keySet()));
prefsWriter.putString(COOKIE_NAME_PREFIX + name,
encodeCookie(new SerializableCookie(cookie)));
prefsWriter.commit();
}
#Override
public synchronized void clear() {
// Clear cookies from persistent store
SharedPreferences.Editor prefsWriter = cookiePrefs.edit();
for (String name : cookies.keySet()) {
prefsWriter.remove(COOKIE_NAME_PREFIX + name);
}
prefsWriter.remove(COOKIE_NAME_STORE);
prefsWriter.commit();
// Clear cookies from local store
cookies.clear();
}
#Override
public synchronized boolean clearExpired(Date date) {
boolean clearedAny = false;
SharedPreferences.Editor prefsWriter = cookiePrefs.edit();
for (ConcurrentHashMap.Entry<String, Cookie> entry : cookies.entrySet()) {
String name = entry.getKey();
Cookie cookie = entry.getValue();
if (cookie.isExpired(date)) {
// Clear cookies from local store
cookies.remove(name);
// Clear cookies from persistent store
prefsWriter.remove(COOKIE_NAME_PREFIX + name);
// We've cleared at least one
clearedAny = true;
}
}
// Update names in persistent store
if (clearedAny) {
prefsWriter.putString(COOKIE_NAME_STORE,
TextUtils.join(",", cookies.keySet()));
}
prefsWriter.commit();
return clearedAny;
}
#Override
public synchronized List<Cookie> getCookies() {
return new CopyOnWriteArrayList<Cookie>(cookies.values());
}
//
// Cookie serialization/deserialization
//
protected synchronized String encodeCookie(SerializableCookie cookie) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
ObjectOutputStream outputStream = new ObjectOutputStream(os);
outputStream.writeObject(cookie);
} catch (Exception e) {
return null;
}
return byteArrayToHexString(os.toByteArray());
}
protected synchronized Cookie decodeCookie(String cookieStr) {
byte[] bytes = hexStringToByteArray(cookieStr);
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
Cookie cookie = null;
try {
ObjectInputStream ois = new ObjectInputStream(is);
cookie = ((SerializableCookie) ois.readObject()).getCookie();
} catch (Exception e) {
e.printStackTrace();
}
return cookie;
}
// Using some super basic byte array <-> hex conversions so we don't have
// to rely on any large Base64 libraries. Can be overridden if you like!
protected synchronized String byteArrayToHexString(byte[] b) {
StringBuffer sb = new StringBuffer(b.length * 2);
for (byte element : b) {
int v = element & 0xff;
if (v < 16) {
sb.append('0');
}
sb.append(Integer.toHexString(v));
}
return sb.toString().toUpperCase();
}
protected synchronized byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character
.digit(s.charAt(i + 1), 16));
}
return data;
}
}
Do something like this:
httpClient.setCookieStoreage(new PersistentCookieStore(this)) in your application subclass where you init the httpclient
You are probably seeing a nasty, long-standing Android bug that causes the symptoms you are describing. Have a look at my answer here: https://stackoverflow.com/a/16447508/769265
You probably have to add following code inside the onCreate() event of launcher Activity.
if (!isTaskRoot()) {
final Intent intent = getIntent();
final String action = intent.getAction();
if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && action != null && action.equals(Intent.ACTION_MAIN)) {
finish();//Launcher Activity is not the root. So,finish it instead of launching
return;
}
}
android:launchMode="singleInstance"
android:alwaysRetainTaskState="true"
Try adding this two attributes to your Activity in manifest, this will make sure newIntent is called when activity is resumed from background.

Sort large amount of data before inserting to database

I need to download a large json String. I'm using aQuery for this. Then I need to parse this string in a list of objects (10k +) (I'm using Gson library for this) and insert this list to database (created with GreenDAO). But before inserting I need to sort this list by my objects string field. I'm using Collator class for sorting because this filed may be on different languages. The question is: how to do such a thing using as less memory as possible?
For now I download a String (+String, I've also tryed to use Streams) then parse it (+List) then sorting it (some more objects). I'm doing it in a separate thread but even when it's done the memory not freed. I think this can be solved if I could sort my data when it's already in database (not when selecting it, it's to slow) but I don't know how.
Here is some code.
This is data loading from file. There is the same issue with memory when loading from file too where I'm using InputStream instead of getting JSON string into memory.
public static void getEnciclopediaDataFromFile() {
mRequestStates.put("enc", true);
try {
EncyclopediaParser parser = new EncyclopediaParser(ResourceManager.getResourceManager().loadFile("enc_data"),
ResourceManager.getResourceManager().loadFile("enc_data"),
1361531132);
parser.start();
} catch (Exception e) {
mRequestStates.put("enc", false);
EventBus.getDefault().post(EVENT_ENCYCLOPEDIA_DOWNLOAD_COMPLETE);
}
}
Here is parser Thread. There are two constructors - one for loading from web (string param) another for loading from file (InputStream param).
private static class EncyclopediaParser extends Thread {
// -----------------------------------------------------------------------
//
// Fields
//
// -----------------------------------------------------------------------
private String mJsonData;
private Reader mTitlesReader;
private Reader mContentReader;
private long mUpdateTime;
// -----------------------------------------------------------------------
//
// Constructor
//
// -----------------------------------------------------------------------
public EncyclopediaParser(String jsonData, long updateTime) {
mJsonData = jsonData;
mUpdateTime = updateTime;
this.setPriority(Thread.NORM_PRIORITY - 1);
}
public EncyclopediaParser(Reader titlesReader, Reader contentReader, long updateTime) {
mTitlesReader = titlesReader;
mContentReader = contentReader;
mUpdateTime = updateTime;
this.setPriority(Thread.NORM_PRIORITY - 1);
}
// -----------------------------------------------------------------------
//
// Methods
//
// -----------------------------------------------------------------------
#Override
public void run() {
Type type;
try {
List<ArticleContent> content = null;
type = new TypeToken<Collection<ArticleContent>>(){}.getType();
if(mContentReader == null)
content = new Gson().fromJson(mJsonData, type);
else
content = new Gson().fromJson(mContentReader, type);
List<ArticleTitle> titles = null;
type = new TypeToken<Collection<ArticleTitle>>(){}.getType();
if(mTitlesReader == null)
titles = new Gson().fromJson(mJsonData, type);
else
titles = new Gson().fromJson(mTitlesReader, type);
for(ArticleTitle title : titles)
title.setTitle(title.getTitle().trim());
TitlesComparator titlesComparator = new TitlesComparator();
Collections.sort(titles, titlesComparator);
for(int i = 0; i < titles.size(); ++i) //sorting enc data
titles.get(i).setOrderValue((long)i);
//create sections data
Collator collator = Collator.getInstance(Locale.GERMAN);
collator.setStrength(Collator.PRIMARY);
ArrayList<String> sectionNamesList = new ArrayList<String>();
ArrayList<Integer> sectionIndexesList = new ArrayList<Integer>();
String prevLetter = "";
for (int i = 0; i < titles.size(); ++i) {
if(titles.get(i).getTitle().length() > 0){
if(!Character.isLetter(titles.get(i).getTitle().charAt(0))) {
if( !sectionNamesList.contains("#")) {
sectionNamesList.add("#");
sectionIndexesList.add(i);
}
}
else if(collator.compare(titles.get(i).getTitle().substring(0, 1), prevLetter) > 0) {
sectionNamesList.add(titles.get(i).getTitle().substring(0, 1).toUpperCase(Locale.GERMAN));
sectionIndexesList.add(i);
}
prevLetter = titles.get(i).getTitle().substring(0, 1);
}
}
String[] sectionNames = new String[sectionNamesList.size()]; //use lists instead
Integer[] sectionIndexes = new Integer[sectionIndexesList.size()];
sectionNamesList.toArray(sectionNames);
sectionIndexesList.toArray(sectionIndexes);
AppData.setSectionIndexes(Utils.convertIntegers(sectionIndexes));
AppData.setSectionNames(sectionNames);
GreenDAO.getGreenDAO().insertArticles(titles, content);
AppData.setEncyclopediaUpdateTime(mUpdateTime);
mRequestStates.put("enc", false);
if(mTitlesReader != null)
mTitlesReader.close();
if(mContentReader != null)
mContentReader.close();
} catch (Exception e) {
Log.e("Server", e.toString());
} finally {
EventBus.getDefault().post(EVENT_ENCYCLOPEDIA_DOWNLOAD_COMPLETE);
}
}
}
All GreenDAO objects are static. Parsing is done only on the first launch (from file) and by "update" button click (from web). I've noticed that even if I'll relaunch my app after initial (from file) parsing is done it'll be using as much memory as after parsing is done for the first time.

How to permanently store parcelable custom object? [duplicate]

This question already has answers here:
Save Bundle to SharedPreferences [duplicate]
(3 answers)
Closed 10 years ago.
I want to store a custom object (let's call it MyObject) permanently so that if it is deleted from memory, I can reload it in my Activity/Fragment onResume() method when the app starts again.
How can I do that? SharedPreferences doesn't seem to have a method for storing parcelable objects.
If you need to store it in SharedPreferences, you can parse your object to a json string and store the string.
private Context context;
private MyObject savedObject;
private static final String PREF_MY_OBJECT = "pref_my_object";
private SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
private Gson gson = new GsonBuilder().create();
public MyObject getMyObject() {
if (savedObject == null) {
String savedValue = prefs.getString(PREF_MY_OBJECT, "");
if (savedValue.equals("")) {
savedObject = null;
} else {
savedObject = gson.fromJson(savedValue, MyObject.class);
}
}
return savedObject;
}
public void setMyObject(MyObject obj) {
if (obj == null) {
prefs.edit().putString(PREF_MY_OBJECT, "").commit();
} else {
prefs.edit().putString(PREF_MY_OBJECT, gson.toJson(obj)).commit();
}
savedObject = obj;
}
class MyObject {
}
You can write your Bundle as a parcel to disk, then get the Parcel later and use the Parcel.readBundle() method to get your Bundle back.

Android, SharedPreference lost when phone reboot

I got a strange problem, that my app's SharedPreference seems lost some specific keys (not all) when the phone reboot.
Have you ever meet this problem? I used that key to store a serialized object and I did that in my own Application class.
public class Application extends android.app.Application {
static String key = "favs";
SharedPreferences settings;
public Favs favs;
#Override
public void onCreate() {
super.onCreate();
settings = PreferenceManager.getDefaultSharedPreferences(this);
String value = settings.getString(key, "");
if (value != null && value.length() > 0) {
try {
Favs = (Favs ) deSerialize(value.getBytes());
} catch (Exception ex) {
}
}
if(favs == null)
favs = new Favs ();
}
public void storeFavss() {
if (favs == null)
return;
try {
byte[] bytes = serialize(favs );
if(bytes != null)
{
String s = new String(bytes);
settings.edit().putString(key, s);
settings.edit().commit();
}
} catch (Exception ex) {
}
}
After debugging, I will show my own anwser here, hope it can help others.
the code below is bad. it seems the edit() method returns a new object each time.
settings.edit().putString(key, s);
settings.edit().commit();
If you are saving some serialized object bytes in the SharedPreference, Base64 it!
favs = (Favs ) deSerialize(value.getBytes());

Categories

Resources