危險的SharedPreference操做

    Android開發中常常用到SharedPreference來存儲一些配置數據。它的API比較簡單,易用。可是在一次簡單的bug排查中發現了一個很是有意思的問題。如今就把這個問題和分析結果寫下來,僅供參考。 java

    咱們的一個模塊在SharedPreference中寫了一條數據,結果發現重啓手機以後,SharedPreference中全部的數據都丟失了。 android

    這個問題很嚴重,沿着邏輯分支走了幾遍,不像是誤刪除的結果。回過頭來仔細看了一下最後一次SharedPreference中寫入的數據,才轟然大悟。 app

<map>
<boolean value="true">
</map>

    問題出在:寫入數據的key是空,只有value是true。這裏有兩個問題。第一爲何key爲空。第二爲何會致使SharedPreference全部的數據丟失? 函數

    第一個問題是產品邏輯的bug。 google

    第二個問題的分析以下: spa

    1)SharedPreference的實現類是android.app.SharedPreferencesImpl。當該類初始化的時候,會從XML文件中把保存的內容加載的內存中。 code

private void loadFromDiskLocked() {
        ..........
        Map map = null;
        FileStatus stat = new FileStatus();
        if (FileUtils.getFileStatus(mFile.getPath(), stat) && mFile.canRead()) {
            try {
                BufferedInputStream str = new BufferedInputStream(
                        new FileInputStream(mFile), 16*1024);
                map = XmlUtils.readMapXml(str);
                str.close();
            } catch (XmlPullParserException e) {
                Log.w(TAG, "getSharedPreferences", e);
            } catch (FileNotFoundException e) {
                Log.w(TAG, "getSharedPreferences", e);
            } catch (IOException e) {
                Log.w(TAG, "getSharedPreferences", e);
            }
        }
        mLoaded = true;
        if (map != null) {
            mMap = map;
            mStatTimestamp = stat.mtime;
            mStatSize = stat.size;
        } else {
            mMap = new HashMap<String, Object>();
        }
        notifyAll();
    }

    2) XmlUtils.readMapXml(str)中發生了什麼事情? 最後追蹤到這樣一個函數: xml

public static final HashMap readThisMapXml(XmlPullParser parser, String endTag, String[] name)
            throws XmlPullParserException, java.io.IOException
    {
        HashMap map = new HashMap();

        int eventType = parser.getEventType();
        do {
            if (eventType == parser.START_TAG) {
                Object val = readThisValueXml(parser, name);
                if (name[0] != null) {
                    //System.out.println("Adding to map: " + name + " -> " + val);
                    map.put(name[0], val);
                } else {
                    throw new XmlPullParserException(
                            "Map value without name attribute: " + parser.getName());
                }
            } else if (eventType == parser.END_TAG) {
                if (parser.getName().equals(endTag)) {
                    return map;
                }
                throw new XmlPullParserException(
                        "Expected " + endTag + " end tag at: " + parser.getName());
            }
            eventType = parser.next();
        } while (eventType != parser.END_DOCUMENT);

        throw new XmlPullParserException(
                "Document ended before " + endTag + " end tag");
    }

    看到這裏就清楚了,由於最開始的那個XML文件中boolean只有value,沒有name,致使name[0] == null,拋出異常。結果整個返回的HashMap是空。 內存

    Google在Issue 63463中fix了這個問題: 開發

    http://code.google.com/p/android/issues/detail?id=63463

    簡單的講就是:SharedPreference在讀/寫的時候支持null key,而再也不是拋異常了。

    相關的討論在這裏:

    https://groups.google.com/forum/#!topic/android-developers/JpDzZtbrjfA

相關文章
相關標籤/搜索