Was ist anstelle von "addPreferencesFromResource" in einer PreferenceActivity zu verwenden?

360

Ich habe gerade festgestellt, dass die Methode in der Android-Dokumentation ( Referenzeintrag ) addPreferencesFromResource(int preferencesResId)als veraltet markiert ist .

Leider ist in der Beschreibung der Methode keine alternative Methode angegeben.

Welche Methode sollte stattdessen verwendet werden, um eine PreferenceScreen.xml mit der passenden PreferenceActivity zu verbinden?

mweisz
quelle
2
Ein sehr einfacher Ansatz wird von WannaGetHigh unter stackoverflow.com/questions/23523806/…
Sabin
Die dortige Lösung wird noch verwendet addPreferencesFromResource(int preferencesResId). Vermisse ich etwas
Jammo
@Jammo Ja, aber es wurde von der Aktivität in das Fragment verschoben, um die neue Vorgehensweise widerzuspiegeln -> Fragment.
WannaGetHigh

Antworten:

332

In der Beschreibung der Methode wird keine alternative Methode angegeben, da der bevorzugte Ansatz (ab API-Ebene 11) darin besteht, PreferenceFragment- Objekte zu instanziieren , um Ihre Einstellungen aus einer Ressourcendatei zu laden. Den Beispielcode finden Sie hier: PreferenceActivity

verherrlichtHacker
quelle
Ich danke Ihnen sehr für Ihre Antwort. Ich habe nur veraltete Anweisungen von "Video2Brain-Android Development" befolgt, die mich dazu veranlassten, die Version der Methode von PreferenceActivity zu verwenden. Übrigens: Ich würde Ihre Antwort gerne als nützlich bewerten, wenn ich nur könnte.
Mweisz
33
Nur wenn das PreferenceFragment im Kompatibilitätspaket enthalten wäre, wäre es sinnvoll, es zu verwenden. Stackoverflow.com/questions/5501431/…
christoff
1
Da ich Action Bar Sherlock verwende, bin ich dem folgenden Blog gefolgt, um dieses Problem zu lösen. Siehe ... commonsware.com/blog/2012/10/16/…
Jemand irgendwo
2
Sie müssen jedoch addPreferencesFromResource (int PreferencesID) aufrufen, wenn die App abwärtskompatibel mit API-Level ab 11 (Android 3.0) sein soll. Aber ich denke, Sie könnten auch diese alten Geräte in Betracht ziehen.
Einar Sundgren
5
@EinarSundgren Ich bin Nexus One-Besitzer und meine maximal verfügbare Version ist 2.2: Du wirst mich nicht aufhalten! Ich werde nie veraltet sein! Durch die Kraft von Grayskull ... Ich habe die Kraft!
TechNyquist
186

Um der richtigen Antwort oben weitere Informationen hinzuzufügen, haben Sie nach dem Lesen eines Beispiels von Android-er festgestellt, dass Sie Ihre Präferenzaktivität einfach in ein Präferenzfragment konvertieren können. Wenn Sie die folgende Aktivität haben:

public class MyPreferenceActivity extends PreferenceActivity
{
    @Override
    protected void onCreate(final Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.my_preference_screen);
    }
}

Die einzigen Änderungen, die Sie vornehmen müssen, sind das Erstellen einer internen Fragmentklasse, das Verschieben der addPreferencesFromResources()in das Fragment und das Aufrufen des Fragments aus der Aktivität wie folgt :

public class MyPreferenceActivity extends PreferenceActivity
{
    @Override
    protected void onCreate(final Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        getFragmentManager().beginTransaction().replace(android.R.id.content, new MyPreferenceFragment()).commit();
    }

    public static class MyPreferenceFragment extends PreferenceFragment
    {
        @Override
        public void onCreate(final Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.my_preference_screen);
        }
    }
}

Es kann andere Feinheiten geben, komplexere Präferenzen aus Fragmenten zu ziehen. wenn ja, hoffe ich, dass jemand sie hier notiert.

Garret Wilson
quelle
6
Schön, danke dafür. Java und diese Art des Denkens ist so weit entfernt von meiner netten kleinen .net-Welt :)
Tom
44
Warum sollten sie addPreferencesFromResources()im Handel für PreferenceFragment abwerten ? Aus Anfängersicht sieht es unnötig aus.
Howdy_McGee
4
Anruf erfordert API Level 11
Mehmet
1
Was ist also, wenn sich die API auf Stufe 9 befindet? @mehmet
gumuruh
2
Super Antwort! Gibt es eine Möglichkeit, dies zu erreichen, ohne den Inhalt von android.R.id.content zu ändern? scheinen mir aus irgendeinem Grund unelegant zu sein ... (korrigiere mich, wenn ich falsch
liege
37

@ Garret Wilson Vielen Dank! Als Neuling in der Android-Codierung habe ich mich so viele Stunden lang mit dem Problem der Inkompatibilität von Einstellungen beschäftigt, und ich finde es so enttäuschend, dass die Verwendung einiger Methoden / Ansätze für neue Methoden, die von den älteren APIs nicht unterstützt werden, abgelehnt wurde Sie müssen auf alle möglichen Problemumgehungen zurückgreifen, damit Ihre App auf einer Vielzahl von Geräten funktioniert. Es ist wirklich frustrierend!

Ihre Klasse ist großartig, denn Sie können weiterhin in neuen APIs mit Einstellungen arbeiten, wie sie früher waren, aber sie ist nicht abwärtskompatibel. Da ich versuche, eine breite Palette von Geräten zu erreichen, habe ich ein wenig daran herumgebastelt, damit es sowohl auf Geräten vor API 11 als auch in neueren APIs funktioniert:

import android.annotation.TargetApi;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;

public class MyPrefsActivity extends PreferenceActivity
{
    private static int prefs=R.xml.myprefs;

    @Override
    protected void onCreate(final Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        try {
            getClass().getMethod("getFragmentManager");
            AddResourceApi11AndGreater();
        } catch (NoSuchMethodException e) { //Api < 11
            AddResourceApiLessThan11();
        }
    }

    @SuppressWarnings("deprecation")
    protected void AddResourceApiLessThan11()
    {
        addPreferencesFromResource(prefs);
    }

    @TargetApi(11)
    protected void AddResourceApi11AndGreater()
    {
        getFragmentManager().beginTransaction().replace(android.R.id.content,
                new PF()).commit();
    }

    @TargetApi(11)
    public static class PF extends PreferenceFragment
    {       
        @Override
        public void onCreate(final Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(MyPrefsActivity.prefs); //outer class
            // private members seem to be visible for inner class, and
            // making it static made things so much easier
        }
    }
}

Mit Erfolg in zwei Emulatoren (2.2 und 4.2) getestet.

Warum mein Code so beschissen aussieht:

Ich bin ein Neuling in der Android-Codierung und ich bin nicht der größte Java-Fan.

Um die veraltete Warnung zu vermeiden und Eclipse zum Kompilieren zu zwingen, musste ich auf Anmerkungen zurückgreifen, die jedoch nur Klassen oder Methoden betreffen. Daher musste ich den Code auf zwei neue Methoden verschieben, um dies zu nutzen.

Ich möchte meine XML-Ressourcen-ID nicht zweimal schreiben müssen, wenn ich die Klasse für eine neue PreferenceActivity kopiere und einfüge. Daher habe ich eine neue Variable zum Speichern dieses Werts erstellt.

Ich hoffe, dass dies jemand anderem nützlich sein wird.

PS: Entschuldigen Sie meine Meinung, aber wenn Sie neu kommen und solche Nachteile finden, können Sie nicht anders, als frustriert zu werden!

ecv
quelle
Na ja ... Ich habe gerade bemerkt, dass ich den Namen der äußeren Klasse jedes Mal zweimal ändern muss, wenn ich ihn kopiere und einfüge. Es gibt tatsächlich eine Möglichkeit, dies zu vermeiden, indem Einstellungen an die Innenklasse übergeben werden. Sie dürfen keinen inneren Klassenkonstruktor erstellen, der Einstellungen als Parameter akzeptiert, da dies für von PreferenceFragment abgeleitete Klassen anscheinend nicht empfohlen wird. Außerdem können Sie möglicherweise keine Methode in der inneren Klasse erstellen, um Einstellungen abzurufen und addPreferencesFromResource sofort aufzurufen, da addPreferencesFromResource aufgerufen werden muss, nachdem super.onCreate aufgerufen wurde, und onCreate nicht direkt aufgerufen wird, nachdem die von PreferenceFragment abgeleitete Klasse ...
ecv
... instanziiert worden. Sie müssen also eine neue Variable in der inneren Klasse erstellen, eine öffentliche Set-Methode dafür in der inneren Klasse erstellen und die addPreferencesFromResource dort belassen, wo sie sich nach dem Aufruf von super.onCreate befindet. In onCreate instanziieren Sie die innere Klasse und legen die Einstellungen fest und verwenden Sie es im Aufruf von getFragmentManager () ... wie zuvor.
Ecv
2
Ihr Code war ein Lebensretter! Ich habe versucht, sowohl auf das alte als auch auf das neue Telefon abzuzielen, und 3 Tage verschwendet. Und die Antwort ist so einfach. Vielen Dank
Devdatta Tengshe
22

Mein Ansatz ist Garret Wilsons sehr nahe (danke, ich habe dich gewählt;)

Darüber hinaus bietet es Abwärtskompatibilität mit Android <3.

Ich habe gerade erkannt, dass meine Lösung der von Kevin Remo noch näher kommt . Es ist nur ein bisschen sauberer (da es nicht auf dem Antipattern "Erwartung" beruht ).

public class MyPreferenceActivity extends PreferenceActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
            onCreatePreferenceActivity();
        } else {
            onCreatePreferenceFragment();
        }
    }

    /**
     * Wraps legacy {@link #onCreate(Bundle)} code for Android < 3 (i.e. API lvl
     * < 11).
     */
    @SuppressWarnings("deprecation")
    private void onCreatePreferenceActivity() {
        addPreferencesFromResource(R.xml.preferences);
    }

    /**
     * Wraps {@link #onCreate(Bundle)} code for Android >= 3 (i.e. API lvl >=
     * 11).
     */
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private void onCreatePreferenceFragment() {
        getFragmentManager().beginTransaction()
                .replace(android.R.id.content, new MyPreferenceFragment ())
                .commit();
    }
}

Ein "reales" (aber komplexeres) Beispiel finden Sie unter NusicPreferencesActivity und NusicPreferencesFragment .

Schnatterer
quelle
@SuppressLint("NewApi")- vermeiden - genauer sein. Hast du es für niedrige Apis laufen lassen? Es wird werfenVerifyError
Mr_and_Mrs_D
Ich teste das Obige auf dem Emulator, auf dem API Level 10 ausgeführt wird. Das APK wurde mit SDK Version 19 erstellt. Welche SDK-Version haben Sie zum Erstellen verwendet? Auf welcher Geräte-API-Ebene haben Sie es ausgeführt? Haben Sie es auf dem Emulator oder auf einem physischen Gerät ausgeführt? Wann genau ist der Fehler aufgetreten? Wenn Ihr Gebäude mit SDK <= 16 erstellt wird, lesen Sie diese Antwort .
Schnatterer
Sie verpassen den Punkt - und fügen @Mr_and_Mrs_D hinzu, wenn Sie möchten, dass ich benachrichtigt werde. Für die VE lesen Sie hier: stackoverflow.com/questions/20271593/… . Das @SuppressLint("NewApi")ist nur ein schlechter Stil
Mr_and_Mrs_D
@M Nun, wie wäre es mit einem Vorschlag, wie man @SuppressLint("NewApi")in dieser besonderen Situation vermeiden kann?
Schnatterer
@TargetApi(Build.VERSION_CODES.HONEYCOMB)- Nicht alle Warnungen für eine API :)
Mr_and_Mrs_D
6

Verwenden Sie anstelle von Ausnahmen einfach:

if (Build.VERSION.SDK_INT >= 11)

und verwenden

@SuppressLint("NewApi")

die Warnungen zu unterdrücken.

Peter
quelle
1
weil es nichts anderes tut als Absturz: D
Ishtiaq
1
Wenn es abstürzt ... dann versuchen Sie es zu fangen: D
Gumuruh
0

Anstatt a PreferenceActivityzum direkten Laden von Einstellungen zu verwenden, verwenden Sie ein AppCompatActivityoder ein Äquivalent, PreferenceFragmentCompatdas a lädt und Ihre Einstellungen lädt. Es ist Teil der Support-Bibliothek (jetzt Android Jetpack) und bietet Kompatibilität zurück zu API 14.

Fügen Sie in Ihrem build.gradleeine Abhängigkeit für die Bibliothek zur Unterstützung von Einstellungen hinzu:

dependencies {
    // ...
    implementation "androidx.preference:preference:1.0.0-alpha1"
}

Hinweis: Wir gehen davon aus, dass Sie Ihre XML-Einstellungen bereits erstellt haben.

Erstellen Sie für Ihre Aktivität eine neue Aktivitätsklasse. Wenn Sie Materialthemen verwenden, sollten Sie ein erweitern AppCompatActivity, aber Sie können damit flexibel sein:

public class MyPreferencesActivity extends AppCompatActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_preferences_activity)
        if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.fragment_container, MyPreferencesFragment())
                    .commitNow()
        }
    }
}

Nun zum wichtigen Teil: Erstellen Sie ein Fragment, das Ihre Einstellungen aus XML lädt:

public class MyPreferencesFragment extends PreferenceFragmentCompat {

    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        setPreferencesFromResource(R.xml.my_preferences_fragment); // Your preferences fragment
    }
}

Weitere Informationen finden Sie in den Android Developers- Dokumenten für PreferenceFragmentCompat.

Willie Chalmers III
quelle