MBH MBH - 5 months ago 28
Android Question

SharedPreferences to a custom path - Android

I want to keep my SharedPreferences xml in a different place where default path is the application package.

Can we set a custom path for android SharedPreferences and use it while it is in that path ?

Answer

You can create a adapter to get preferences.

First, create an interface IPreferences (Not necessary but make your life easier if you want to change it back or change to another method):

public interface IPreferences {
    boolean contains(String key);
    int getInt(String key, int defValue);
    String getString(String key, String defValue);
    void putInt(String key, int value);
    void putString(String key, String value);
}

(Some methods are left out, most of them are redundant)

Then, you implement with a xml storage class XMLPreferences.

public class XMLPreferences implements IPreferences {
    private final String path;

    public XMLPreferences(String path) {
        this.path = path;
    }

    @Override
    public boolean contains(String key) {
        return getContentByKey(key) == null;
    }

    @Override
    public int getInt(String key, int defValue) {
        if( getContentByKey(key) == null)
            return defValue;
        return Integer.valueOf(key);
    }

    @Override
    public String getString(String key, String defValue) {
        if( getContentByKey(key) == null)
            return defValue;
        return defValue;
    }

    @Override
    public void putInt(String key, int value) {
        putContentByKey(key, value);
    }

    @Override
    public void putString(String key, String value) {
        putContentByKey(key, value);
    }

    private String getContentByKey(String key) {
        try {
            FileInputStream fileInputStream = new FileInputStream(path);
            DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            Document dom = builder.parse(fileInputStream);
            Element root = dom.getDocumentElement();
            NodeList nodes = root.getElementsByTagName(key);
            if (nodes.getLength() > 0)
                return nodes.item(0).getTextContent();
        } catch (ParserConfigurationException | SAXException | IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private void putContentByKey(String key, String content) {
        try {
            FileInputStream fileInputStream = new FileInputStream(path);
            DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            Document dom = builder.parse(fileInputStream);
        Element root = dom.getDocumentElement();
            NodeList nodes = root.getElementsByTagName(key);
            if (nodes.getLength() > 0)
                nodes.item(0).setTextContent(content);
            else {
                Element newElement = dom.createElement(key);
                newElement.setTextContent(content);
                root.appendChild(newElement);
            }
            Transformer transformer = TransformerFactory.newInstance().newTransformer();
            Result output = new StreamResult(new File(path));
            Source input = new DOMSource(dom);
            transformer.transform(input, output);
        } catch (ParserConfigurationException | SAXException | IOException | TransformerException e) {
            e.printStackTrace();
        }
    }
}

Finally, you can call the following:

IPreferences pref = new XMLPreferences(YOUR_PATH);

Later, if you want to change the implementation, you can implement a new class with IPreferences. Then, you can just change the initialization without changing other parts.

P.S. This uses DOM Praser which may facing performance issue if you have a large XML file. You may want use other XML Praser instead