2016-06-02 37 views
0

Aktuelles Verhalten von PreferenceFragment: Bei der ersten Anzeige auf dem Bildschirm schreibt PreferenceFragment in den zugeordneten SharedPreferences alle in PreferenceScreen definierten XML-Ressourcen. Ich habe dieses Paar mal getestet und PreferenceFragment sowie PreferenceActivity schreiben alle Voreinstellungen standardmäßig auf SharedPreferences, wenn der Benutzer die Einstellungsaktivität öffnet, auch wenn er sie sofort schließt, ohne etwas zu berühren.Verhindern, dass PreferenceFragment Standardeinstellungen in SharedPreferences schreibt

Problem: Wenn ich in der nächsten Version meiner App beschließe, einige Standardbenutzereinstellungen zu ändern, werden sie nicht auf die Geräte angewendet, bei denen der Benutzer mindestens einmal die App-Einstellungen geöffnet hat, weil PreferenceFragment alle Standardwerte auf SharedPreferences geschrieben hat. Ich weiß, dass ich neue Standardwerte erneut anwenden kann, indem ich alle Werte in SharedPreferences überschreibe, nicht nur Standard, sondern auch vom Benutzer gewählt. Das Zurücksetzen der Benutzereinstellungen im App-Update ist jedoch völlig inakzeptabel. Das Problem ist also, dass wir nicht unterscheiden können, wenn eine bestimmte Präferenz explizit durch den Benutzer oder dessen Standardvorgabe festgelegt wurde, die bei der ersten Anzeige auf dem Bildschirm durch geschrieben wurde.

Was ich will: Wenn der Benutzer eine bestimmte Präferenz hat, was auch immer er gewählt hat, sollte ich dies nicht mit meinen aktualisierten App-Standards berühren, auch wenn die Benutzerauswahl mit meinem alten Standard übereinstimmt. Aber wenn Benutzer nicht explizit gewählt wurde, möchte ich, dass meine neuen Standardeinstellungen für ihn mit App-Update arbeiten.

Also: Wie zu verhindern, schreiben von Standardvoreinstellungen Werte von PreferenceFragment zu zugeordneten SharedPreferences?

+0

, wenn der Benutzer nichts besonders bevorzugt ändern es in der Präferenz XML-Datei nicht angezeigt, in der alle Werte – pskink

+0

gespeichert sind @pskink ich diese paar Mal und PreferenceFragment auch getestet, wie PreferenceActivity alle Einstellungen standardmäßig SharedPreferences begehen wenn der Benutzer zum ersten Mal das Einstellungsfenster öffnet. Ich war überrascht, als es notierte – Dima

+0

'... und PreferenceActivity commit alle Voreinstellungen Standard SharedPreferences ...' Sie meinen, die physische Datei '/data/data/your.package/ shared_prefs/your.package_preferences.xml 'wird mit aufgefüllt die Standardwerte? für einen Test-Dump diese Datei, dann fügen Sie einige neue Präferenz, dump die Datei erneut, ändern Sie diese Einstellung und dump diese Datei erneut – pskink

Antwort

1

Nach dem Studium der Quellen fand ich einen Weg, um das gewünschte Verhalten zu erreichen.

Der einzige Ort, an dem echte Schreiben an SharedPreferences auftritt, ist es eine Reihe von persist[Type] Methoden in Preference Klasse. Und Unterklassen von Preference rufen Sie normalerweise persist[Type] Methode nur in einzelnen internen Methode, die über alle Unterklassen ähnliche Struktur hat. Zum Beispiel Verfahren von TwoStatePreference, dass übergeordnete Klasse von ChekBoxPreference und SwitchPreference ist:

public void setChecked(boolean checked) { 
    boolean changed = this.mChecked != checked; 
    if(changed || !this.mCheckedSet) { 
     this.mChecked = checked; 
     this.mCheckedSet = true; 
     this.persistBoolean(checked); 
     if(changed) { 
      this.notifyDependencyChange(this.shouldDisableDependents()); 
      this.notifyChanged(); 
     } 
    } 
} 

Als nächstes setChecked Methode von TwoStatePreference wird in etwa fünf anderen Methoden genannt, und zwei dieser Anrufe können Standardwert produzieren zu SharedPreferences werden verpflichtet . Hier ist zuerst:

@Override 
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) { 
    setChecked(restoreValue ? getPersistedBoolean(mChecked) 
      : (Boolean) defaultValue); 
} 

Und zweitens:

@Override 
protected void onRestoreInstanceState(Parcelable state) { 
    if (state == null || !state.getClass().equals(SavedState.class)) { 
     // Didn't save state for us in onSaveInstanceState 
     super.onRestoreInstanceState(state); 
     return; 
    } 

    SavedState myState = (SavedState) state; 
    super.onRestoreInstanceState(myState.getSuperState()); 
    setChecked(myState.checked); 
} 

Und hier ist die Lösung, benutzerdefinierte Klasse, die SwitchPreferenceCompat Unterklassen und verhindert in zwei oben Anrufe begehen:

public class MySwitchPref extends SwitchPreferenceCompat 
{ 
    private boolean mAllowPersist; 

    @Override 
    protected boolean persistBoolean(boolean value) { 
     if (mAllowPersist) { 
      return super.persistBoolean(value); 
     } 
     return false; 
    } 

    @Override 
    protected void onSetInitialValue(boolean restoreValue, 
      Object defaultValue) { 
     mAllowPersist = false; 
     super.onSetInitialValue(restoreValue, defaultValue); 
     mAllowPersist = true; 
    } 

    @Override 
    protected void onRestoreInstanceState(Parcelable state) { 
     mAllowPersist = false; 
     super.onRestoreInstanceState(state); 
     mAllowPersist = true; 
    } 

    public MySwitchPref(Context context, AttributeSet attrs, 
      int defStyleAttr, int defStyleRes) { 
     super(context, attrs, defStyleAttr, defStyleRes); 
    } 

    public MySwitchPref(Context context, AttributeSet attrs, 
      int defStyleAttr) { 
     super(context, attrs, defStyleAttr); 
    } 

    public MySwitchPref(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    public MySwitchPref(Context context) { 
     super(context); 
    } 
} 

Sie sollten Ersetzen Sie Ihre SwitchPreferenceCompat-Deklaration in Xml PreferenceScreen zu dieser Unterklasse und alles sollte funktionieren, ich habe es getestet. Und wenn Sie andere Voreinstellungen als SwitchPreference verwenden, sollten Sie ihr Verhalten ebenfalls unterklassifizieren und überschreiben.

Vorsicht: Diese Lösung basiert auf der internen Realisierung der aktuellen Bibliothek com.android.support:preference-v7:23.4.0. Das kann sich bei zukünftigen Releases ändern. Wenn Sie also eine andere Bibliotheksversion verwenden oder eine nicht unterstützte Implementierung verwenden, sollten Sie in die Quelle schauen und sicherstellen, dass es keine anderen Aufrufe gibt, Werte in SharedPreferences zu erhalten, außer zwei, die ich überschrieben habe.Wenn Sie auch andere Unterklassen von Preference verwenden, nicht nur SwitchPreference, sollten Sie prüfen, ob andere Aufrufe Werte in SharedPreferences beibehalten.

Verwandte Themen