12

共有設定を何度も使用しましたが、何らかの理由で、テストしている新しいアプリに変更が保存されていません。重要なコードの抜粋は次のとおりです。

SharedPreferences sp = getSharedPreferences(getString(R.string.key_preferences), MODE_PRIVATE);
Set<String> widgets = sp.getStringSet(getString(R.string.key_widgets), (new HashSet<String>()));
widgets.add(name + " " + Integer.toString(appWidgetId) + " " + address);
sp.edit().putStringSet(getString(R.string.key_widgets), widgets).commit();

ロギングを使用してウィジェットがセットに追加されていることを確認しましたが、更新されたセットが保存されることはありません。最後の行を...に変更すると

sp.edit().putStringSet(getString(R.string.key_widgets), widgets).putString("testkey", "testvalue").commit();

...その後、すべてがうまく保存されます。私は何が欠けていますか?

*アップデート:

これも機能することがわかりました。

SharedPreferences sp = getSharedPreferences(getString(R.string.key_preferences), MODE_PRIVATE);
Set<String> widgets = sp.getStringSet(getString(R.string.key_widgets), (new HashSet<String>()));
Set<String> newWidgets = new HashSet<String>();
for (String widget : widgets) newWidgets.add(widget);
newWidgets.add(name + " " + Integer.toString(appWidgetId) + " " + address);
sp.edit().putStringSet(getString(R.string.key_widgets), newWidgets).commit();

おそらく、設定を保存するためにエディター用の新しいオブジェクトを作成する必要があることについて、ドキュメントで何かを見逃していました。

*更新2:

エディターオブジェクトを作成しても違いはありません。

SharePreferences.Editor spe = sp.edit();
spe.putStringSet(getString(R.string.key_widgets), widgets)
spe.commit();
4

6 に答える 6

17

ドキュメントをもっと注意深く読む必要があります

getStringSetによると

この呼び出しによって返されるsetインスタンスを変更してはならないことに注意してください。保存されたデータの一貫性は保証されません。また、インスタンスを変更する機能も保証されません。

実際、 SharedPreferences.Editorで、後で変更される可能性のあるセットをputStringSetに送信しないように注意する必要があります。変更する前にgetStringSetから返されたセットのコピーを作成し、putStringSetに送信する前にセットのコピーを作成します。

SharedPreferences myPrefs = getSharedPreferences(myPrefName, MODE_PRIVATE);
HashSet<String> mySet = new HashSet<string>(myPrefs.getStringSet(mySetKey, new HashSet<string()));
....
SharedPreferences.Editor myEditor = myPrefs.edit();

次に、

myEditor.putStringSet(mySetKey, new HashSet<String>(mySet));

また

myEditor.putStringSet(mySetKey, (Set<String>) mySet.clone());
于 2013-12-29T20:59:30.897 に答える
10

チケの答えを少し改善したいと思います。

原因

commit()がディスクに保存されなかった理由は、最初にメモリにコミットしてからディスクの書き込みが完了するのを待つ実装(v4.0.1以降変更なし)を見ると明らかです。

public boolean commit() {
    MemoryCommitResult mcr = commitToMemory();
    SharedPreferencesImpl.this.enqueueDiskWrite(
        mcr, null /* sync write on this thread okay */);
    try {
        mcr.writtenToDiskLatch.await();
    } catch (InterruptedException e) {
        return false;
    }
    notifyListeners(mcr);
    return mcr.writeToDiskResult;
}

重要なのは、 getStringSet()から同じインスタンスでputStringSet()を呼び出しても、変更は検出されないということです。

// Returns true if any changes were made
private MemoryCommitResult commitToMemory() {
    MemoryCommitResult mcr = new MemoryCommitResult();
    ...
            for (Map.Entry<String, Object> e : mModified.entrySet()) {
                String k = e.getKey();
                Object v = e.getValue();
                ...
                    if (mMap.containsKey(k)) {
                        Object existingValue = mMap.get(k);
                        if (existingValue != null && existingValue.equals(v)) {
                            continue;
                        }
                    }
                    mMap.put(k, v);
                }

                mcr.changesMade = true;
                ...
            }
            ...
        }
    }
    return mcr;
}

変更が加えられていないため、writeToFile()はディスクへの書き込みを喜んでスキップし、成功フラグを設定します。

private void writeToFile(MemoryCommitResult mcr) {
    // Rename the current file so it may be used as a backup during the next read
    if (mFile.exists()) {
        if (!mcr.changesMade) {
            // If the file already exists, but no changes were
            // made to the underlying map, it's wasteful to
            // re-write the file.  Return as if we wrote it
            // out.
            mcr.setDiskWriteResult(true);
            return;
        }
        ...
    }
    ...
}

解決

同じSharedPreferenceキーに保存する前に、Chikeの回答を参照し、文字列セットのコピーを作成してください。

于 2015-09-08T11:42:27.357 に答える
1

Editorオブジェクトを保存してから、commit()(Android 2.3より前)またはapply()(Android 2.3以降)を呼び出す必要があります。

SharedPreferences.Editor editor = sp.edit();
editor.put...
editor.commit();
于 2012-05-23T12:41:18.180 に答える
1

あなたが説明しているのと同じ問題が発生しています。

ブール値と文字列の設定は問題なく保存されますが、文字列セットを保存しようとすると、問題が発生します。

文字列セットに最初の要素を追加して保存すると、機能します。しかし、2つ目を追加しようとすると、メモリに追加されます(その設定に保存されているすべての要素を表示するビューを更新できます)。アプリケーションを強制的に閉じて再起動すると、共有設定には最初の要素のみが追加されます。

コードをデバッグしたところ、新しい文字列を追加しても、文字列を保存したHashSetは問題ないことがわかりましたが、変更は永続ストレージに書き込まれません。

于 2012-12-17T10:27:55.643 に答える
0

共有設定には次の構造を使用します。

1.オブジェクトを作成します

SharedPreferences myPrefs = context.getSharedPreferences(PREF_NAME, MODE_WORLD_READABLE);

2.共有設定に値を保存するには:

共有設定用のエディターを作成します。

SharedPreferences.Editor prefsEditor = myPrefs .edit();

次に、エディターに値を入力します。

prefsEditor.putString("KEY", VALUE);

次に、変更をコミットして共有設定を保存します。

prefsEditor.commit();
于 2012-05-23T13:13:16.507 に答える
0

以下のコードをonCreateメソッドに入れると、アプリを再起動するたびにリセットされます。

    preferences.edit().putInt(...).apply();

代わりに、ここに記載されている方法を使用してください:https ://stackoverflow.com/a/28789934/11266070

    SharedPreferences sharedPrefs = getSharedPreferences("sp_name", MODE_PRIVATE);
    SharedPreferences.Editor ed;
    if(!sharedPrefs.contains("initialized")){
        ed = sharedPrefs.edit();

        //Indicate that the default shared prefs have been set
        ed.putBoolean("initialized", true);

        //Set some default shared pref
        ed.putString("myDefString", "wowsaBowsa");

        ed.commit();
    }  

これが誰かに思い出させることを願っています...

于 2020-01-03T08:21:47.580 に答える