1

Supposed I had 2 sharedPreferences files, one was created via "PreferenceManager.getDefaultSharedPreferences(...);" and one via getSharedPreferences(someString, Context.MODE_PRIVATE)", and I know that the keys are unique in both.

What would it take to move all keys&values from one file, to the other?

Is there an easy way to move them all?

I was thinking of using code similar to this answer, but won't I need to consider the type of each value there?

EDIT:

This is one way to do it, but it's a bit unsafe, as new types might be added to SharedPreferences in the future, which means it won't be supported:

        final Editor edit = targetSharedPreferences.edit();
        final Map<String, ?> srcSharedPreferenceAll = srcSharedPreference.getAll();
        for (final Entry<String, ?> entry : srcSharedPreferenceAll.entrySet()) {
            if (entry.getValue() instanceof Integer)
                edit.putInt(entry.getKey(), (Integer) entry.getValue());
            else if (entry.getValue() instanceof Boolean)
                edit.putBoolean(entry.getKey(), (Boolean) entry.getValue());
            else if (entry.getValue() instanceof Long)
                edit.putLong(entry.getKey(), (Long) entry.getValue());
            else if (entry.getValue() instanceof String)
                edit.putString(entry.getKey(), (String) entry.getValue());
            else if (entry.getValue() instanceof Float)
                edit.putFloat(entry.getKey(), (Float) entry.getValue());
            else if (entry.getValue() instanceof Set<?>)
                edit.putStringSet(entry.getKey(), (Set<String>) entry.getValue());
        }
        edit.apply();
        srcSharedPreference.edit().clear().apply();

I've succeeded copying the xml tags from one SharedPreference file to the other, but for some reason, it only get noticed by the SharedPreference object on the next session, and not the current one (probably it's cached). Here's the code:

    private static final String DST_XML_FILE = "dst";

    // creating the data, for reading&writing later:
    final SharedPreferences srcSharedPreference = getSharedPreferences(String , Context.MODE_PRIVATE);
    srcSharedPreference.edit().clear().putInt("someInt", 12).putString("someString", "hi").putBoolean("someBoolean", true).apply();
    final SharedPreferences targetSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
    targetSharedPreferences.edit().clear().putInt("someInt2", 23).putString("someString2", "hi there").putBoolean("someBoolean2", false).apply(); 

    //checking content before
    Log.d("AppLog", "before");
    final Map<String, ?> src = srcSharedPreference.getAll();
    Log.d("AppLog", "src:" + src.size());
    final Map<String, ?> targetSharedPreferencesAll = targetSharedPreferences.getAll();
    Log.d("AppLog", "target:" + targetSharedPreferencesAll.size());

    // the moving of the XML tags:
    final PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
    File dstFile = new File(packageInfo.applicationInfo.dataDir, "shared_prefs/" + (VERSION.SDK_INT >= VERSION_CODES.N ? PreferenceManager.getDefaultSharedPreferencesName(this) : getPackageName() + "_preferences") + ".xml");
    File srcFile = new File(packageInfo.applicationInfo.dataDir, "shared_prefs/" + SRC_XML_FILE + ".xml");

    DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
    Node srcNode = docFactory.newDocumentBuilder().parse(srcFile).getFirstChild();
    Node dstNode = docFactory.newDocumentBuilder().parse(dstFile).getFirstChild();
    final NodeList childNodes = srcNode.getChildNodes();
    for (int i = 0; i < childNodes.getLength(); ++i) {
        final Node item = childNodes.item(i);
        Node importedNode = dstNode.getOwnerDocument().importNode(item, true);
        srcNode.removeChild(item);
        dstNode.appendChild(importedNode);
    }
    TransformerFactory transformerFactory = TransformerFactory.newInstance();
    Transformer transformer = transformerFactory.newTransformer();
    DOMSource source = new DOMSource(dstNode);
    StreamResult result = new StreamResult(dstFile);
    transformer.transform(source, result);

    //checking content after
    Log.d("AppLog", "after");
    final Map<String, ?> src = srcSharedPreference.getAll();
    Log.d("AppLog", "src:" + src.size());
    final Map<String, ?> targetSharedPreferencesAll = targetSharedPreferences.getAll();
    Log.d("AppLog", "target:" + targetSharedPreferencesAll.size());
Cœur
  • 37,241
  • 25
  • 195
  • 267
android developer
  • 114,585
  • 152
  • 739
  • 1,270

1 Answers1

1
Map<String,?> keys = prefs.getAll();
for(Map.Entry<String,?> entry : keys.entrySet()){
        Object o = keys.get(entry);
        if (o instanceof Boolean)
        {
            pref2.putBoolean(o);
        }
        if (o instanceof String)
        {
            pref2.putString(o);
        }
        ...
    }
}  
Ashish
  • 183
  • 9
  • Can you please show the code of "put in other pref" ? – android developer Aug 29 '16 at 17:13
  • So I need to check the type of each of the objects? Is there a better option? Maybe handle it all as XML tags instead? – android developer Aug 29 '16 at 17:55
  • You put values in via a `SharedPreferences.Editor`. – Eugen Pechanec Aug 29 '16 at 18:04
  • @EugenPechanec Yes, but is there a better way, that I won't need to check the type of each value in the map ? The current implementation isn't safe, because if there will be new types, it won't support them. – android developer Aug 30 '16 at 07:46
  • 1
    @androiddeveloper There is no quicker way. There will be no more types. And if by any chance yes, you'll update the code accordingly. (When is the last time you stored a string set to shared preferences? Just support the primitives and by done with it.) – Eugen Pechanec Aug 30 '16 at 10:47
  • @EugenPechanec Quicker, not, but safer. I've created the first part of the process, that does the parsing Updated the question). I now need to find out how to modify the other file. – android developer Aug 30 '16 at 18:27
  • @androiddeveloper Quicker as in "look how much time you spent on this already if you could just handle the primitives via standard SharedPreferences and SharedPreferences.Editor API instead". If you want to build a complete solution you'll have to let go of SharedPreferences and **google something like "java merge two xml files"**. – Eugen Pechanec Aug 30 '16 at 18:32
  • @EugenPechanec I've found a way, but for some reason, the SharedPreferences object doesn't notice the changes (probably it's cached) only on the next session. Updated the code I created. Can you check it out? – android developer Aug 30 '16 at 21:20
  • @androiddeveloper You're right about the caches, thanks for pointing that out. Docs even say "Modifications to the preferences must go through an SharedPreferences.Editor object to ensure the preference values remain in a consistent state and control when they are committed to storage." So you'd have to use something like ProcessPhoenix to kill and restart the app which is not viable in production. – Eugen Pechanec Aug 30 '16 at 21:28
  • @EugenPechanec So there is no safe way to do it. I might be able to use reflection to reset its cache, or maybe try to access the SharedPreferences only after the moving process has finished, but both of those are quite dangerous too. – android developer Aug 30 '16 at 21:52
  • @androiddeveloper Or you might just accept the answer. :D Look, even if there will be a new data type in SharedPreferences, you have half a year of platform preview builds to adjust your code. – Eugen Pechanec Aug 30 '16 at 22:13
  • @EugenPechanec The answer you wrote is what I wanted to avoid in the first place (the one I provided a link about), just because of this reason. The only way my solution would work, is that I actually create a totally new SharedPreference file as the merged output. The time for handling changes is not what worries me. It's the fact that whoever uses this, can forget about even checking it out for changes in the SDK. That's why it's unsafe. – android developer Aug 30 '16 at 23:16
  • Anyway, since the API won't probably change, please put the full code as I've provided, and I will accept the answer. I still think there should be a better way. – android developer Aug 30 '16 at 23:18