Home » Android » android – Sharedpreference byte[] value cleared after app killed via 'Force Stop' or task manager

android – Sharedpreference byte[] value cleared after app killed via 'Force Stop' or task manager

Posted by: admin May 14, 2020 Leave a comment

Questions:

Problem

I’m saving a byte[] in my shared preferences. I am able to close the app and reopen it with the value persisting in the Shared Preferences. When running the app and closing it via the ‘Task Manager’ or ‘Force Close’, the Shared Preference value for the byte[] is cleared. I don’t understand this because other values persist fine.

This lead me to believe that this was due to some gson or Shared Preference issue with the byte[] so I converted it to a String and I still have the issue.

Edit:
I save the data during normal activity usage… after onCreate(), for example. It’s not during onPuse() or onDestroy() I forgot to mention this. It would make sense if I did call it here and one or both of those weren’t being called on the ‘Force Close’ scenario.


Shared Preference Code

Slightly modified to remove app specific implementation and data

private static final String SHARED_PREFERENCES_FILE_NAME = "SharedPreferenceName";

    public static void setSharedPreferenceObjectBase64Encoded(Context context, String key, Object object) throws Exception {
        // Need an editor to update shared preference values
        SharedPreferences.Editor editor = context.getSharedPreferences(SHARED_PREFERENCES_FILE_NAME, Context.MODE_PRIVATE).edit();
        Gson gson = new GsonBuilder().serializeNulls().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").create();
        String encodedKey = Base64.encodeToString(key.getBytes(), 0, key.getBytes().length, Base64.DEFAULT);
        String stringObject = gson.toJson(object);
        String encodedObject = Base64.encodeToString(stringObject.getBytes(), 0, stringObject.getBytes().length, Base64.DEFAULT);
        editor.putString(encodedKey, encodedObject);
        editor.apply();
    }

    public static Object getSharedPreferenceObjectBase64Encoded(Context context, String key, Class<? extends Serializable> objectClass) throws Exception {
        // Need an editor to update shared preference values
        SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES_FILE_NAME, Context.MODE_PRIVATE);
        Gson gson = new GsonBuilder().serializeNulls().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").create();
        String encodedKey = Base64.encodeToString(key.getBytes(), 0, key.getBytes().length, Base64.DEFAULT);
        String encodedObject = prefs.getString(encodedKey, null);
        if (encodedObject == null) {
            throw new NullPointerException("encodedObject is null : No shared preference exists for key.");
        }
        String decodedObject = new String(Base64.decode(encodedObject, Base64.DEFAULT));
        if(decodedObject == null){
            throw new NullPointerException("decodedObject is null : Json decoding error.");
        }
        Object resultObject = gson.fromJson(decodedObject, objectClass);
        if (resultObject == null) {
            throw new NullPointerException("resultObject is null : Json decoding error.");
        }
        return resultObject;
    }

`byte[]` Code

public static final String VALUE_KEY= "value.key";

    public static void saveTheValue(Context context, byte[] encryptedPin) {
        try {
            USharedPreferenceManager.setSharedPreferenceObjectBase64Encoded(context, VALUE_KEY, encryptedPin);
        } catch (Exception e) {
        }
    }

    public static byte[] getTheValue(Context context) {
        try {
            return (byte[]) USharedPreferenceManager.getSharedPreferenceObjectBase64Encoded(context, VALUE_KEY, byte[].class);
        } catch (Exception e) {
            return null;
        }
    }

Any input would be greatly appreciated..

Sadly, I haven’t been able to make any progress here. Any thoughts?


Update:

As per Super-califragilistic recommendation, I iterated through the key/value pairs in the SharedPreferences immediately before retrieving the value. I was Base64 encoding my key and value values; in order to read the key to ensure the value was in the SharedPreferences I had to use the keys in plain text. This solved the issue for me as the byte[] value was now being retrieved properly.

This seems strange to me but I can use it as a solution. I would still like to Base64 encode the keys, but it’s not incredibly important.


Current Solution:

Removed the Base64 encoding of the SharedPreference Key for storage and retrieval and the value is now persisting in all cases.

How to&Answers:

This line of code String encodedObject = prefs.getString(encodedKey, null); means if the key does not exist it should return null, hence your key that you are checking does not exist.

To validate if your key/value exist use this code

for(Entry<String, ?> en : sharedPref.getAll().entrySet()){
      en.getKey();//key
      en.getValue();//value
}

you could stop that from happening override onPause() in the Activity or Fragment and call saveTheValue(Context context, byte[] encryptedPin) if you detect you need to save data or have already tried saving data eg.

private boolean forceSaveInOnPause= false;//global variable

//in your saving method
....//after you save
forceSaveInOnPause = true;

//in your onPause of Activity
if(forceSaveInOnPause){       
   //re-save
   forceSaveInOnPause = false;

but since you already have a solution scratch all that 🙂

Answer:

Try once with editor.commit() instead of apply(), see if that works

Answer:

I think using Base64.NO_PADDING instead of Base64.DEFAULT both while reading and writing may solve the problem.