Cosa usare al posto di "addPreferencesFromResource" in PreferenceActivity?


360

Ho appena notato il fatto che il metodo addPreferencesFromResource(int preferencesResId)è contrassegnato come deprecato nella documentazione di Android ( voce di riferimento ).

Sfortunatamente, nessun metodo alternativo è fornito nella descrizione del metodo.

Quale metodo dovrebbe essere usato invece per collegare una preferenzaScreen.xml al PreferenceActivity corrispondente?


2
Un approccio molto semplice è fornito da WannaGetHigh a stackoverflow.com/questions/23523806/...
Sabin

La soluzione lì utilizza ancora addPreferencesFromResource(int preferencesResId). Mi sto perdendo qualcosa ?
Jammo,

@Jammo Sì, ma è stato spostato dall'attività al frammento per riflettere il nuovo modo di farlo -> frammento.
WannaGetHigh

Risposte:


332

Nella descrizione del metodo non viene fornito alcun metodo alternativo poiché l'approccio preferito (a partire dal livello API 11) è l'istanza degli oggetti PreferenceFragment per caricare le preferenze da un file di risorse. Vedi qui il codice di esempio: PreferenceActivity


Grazie mille per la tua risposta. Stavo solo seguendo le istruzioni deprecate di "Sviluppo Video2Brain-Android" che mi hanno portato a utilizzare la versione del metodo PreferenceActivity. Btw: Mi piacerebbe valutare la tua risposta come utile se solo potessi.
mweisz,

33
Ora solo se PreferenceFragment fosse incluso nel pacchetto di compatibilità, avrebbe senso usarlo stackoverflow.com/questions/5501431/…
christoff

1
Da quando uso Action Bar Sherlock, ho seguito il seguente blog per risolvere questo problema, consultare ... commonsware.com/blog/2012/10/16/…
Someone Somewhere

2
Tuttavia, è necessario chiamare addPreferencesFromResource (int PreferencesID) se si desidera che l'app sia retrocompatibile con il livello API più precedente di 11 (Android 3.0). Ma suppongo che potresti considerare anche quei vecchi dispositivi declassati.
Einar Sundgren,

5
@EinarSundgren Sono Nexus Un proprietario e la mia versione massima disponibile è 2.2: non mi fermerai! Non sarò MAI deprecato! Per il potere di Grayskull ... Ho il potere!
TechNyquist,

186

Per aggiungere ulteriori informazioni alla risposta corretta sopra, dopo aver letto un esempio da Android-er ho scoperto che puoi facilmente convertire la tua attività di preferenza in un frammento di preferenza. Se hai la seguente attività:

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

Le uniche modifiche che devi apportare sono la creazione di una classe di frammento interna, lo spostamento addPreferencesFromResources()nel frammento e l'invocazione del frammento dall'attività, in questo modo:

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);
        }
    }
}

Potrebbero esserci altre sottigliezze per rendere le preferenze più complesse dai frammenti; in tal caso, spero che qualcuno li noti qui.


6
Bene, grazie per questo. Java e questo tipo di pensiero sono così lontani dal mio bel piccolo mondo .net :)
Tom,

44
Perché dovrebbero deprezzarsi addPreferencesFromResources()nel commercio per PreferenceFragment? Sembra inutile dal punto di vista del principiante.
Howdy_McGee,

4
La chiamata richiede il livello API 11
mehmet

1
quindi che dire se l'API è al livello 9? @mehmet
gumuruh,

2
Risposta fantastica! c'è un modo per raggiungere questo obiettivo senza cambiare android.R.id.content? mi sembra inelegante per qualche motivo ... (correggimi se sbaglio)
tomer.z

37

@Garret Wilson Grazie mille! Come noob per la codifica Android, sono stato bloccato con il problema dell'incompatibilità delle preferenze per così tante ore e lo trovo così deludente che hanno deprecato l'uso di alcuni metodi / approcci per quelli nuovi che non sono supportati dalle API precedenti quindi dover ricorrere a tutti i tipi di soluzioni alternative per far funzionare la tua app su una vasta gamma di dispositivi. È davvero frustrante!

La tua classe è fantastica, perché ti consente di continuare a lavorare su nuove API con le preferenze come una volta, ma non è compatibile con le versioni precedenti. Dal momento che sto cercando di raggiungere una vasta gamma di dispositivi, ci ho provato un po 'per farlo funzionare nei dispositivi pre API 11 e nelle API più recenti:

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
        }
    }
}

Testato su due emulatori (2.2 e 4.2) con esito positivo.

Perché il mio codice sembra così scadente:

Sono un noob per la codifica Android e non sono il più grande fan di Java.

Per evitare l'avvertimento deprecato e per forzare Eclipse a consentirmi di compilare, ho dovuto ricorrere alle annotazioni, ma queste sembrano influenzare solo le classi o i metodi, quindi ho dovuto spostare il codice su due nuovi metodi per trarne vantaggio.

Non vorrei scrivere il mio ID di risorsa xml due volte ogni volta che copio e incollo la classe per un nuovo PreferenceActivity, quindi ho creato una nuova variabile per memorizzare questo valore.

Spero che questo sia utile a qualcun altro.

PS: Mi dispiace per le mie opinioni supposte, ma quando vieni nuovo e trovi tali handicap, non puoi far altro che frustrarti!


Oh bene ... ho appena notato che avrei dovuto cambiare due volte il nome della classe esterna ogni volta che lo copiavo e lo incollavo. In realtà c'è un modo per evitarlo, passando le preferenze all'innerclass. Non è possibile creare un costruttore di classi interne accettando prefs come parametro poiché apparentemente non è raccomandato per le classi derivate PreferenceFragment. Inoltre, non puoi creare un metodo nella classe interna per ottenere le preferenze e chiamare subito AddPreferencesFromResource, poiché addPreferencesFromResource deve essere chiamato dopo che è stato chiamato super.onCreate e onCreate non viene chiamato subito dopo che la classe derivata PreferenceFragment ha ...
ecv

... stato istanziato. Quindi devi creare una nuova variabile nella classe interna, creare un metodo set pubblico per essa nella classe interna, lasciare addPreferencesFromResource dove si trova dopo la chiamata a super.onCreate, dentro onCreate, creare un'istanza della classe interna, impostare le preferenze e utilizzarlo nella chiamata per getFragmentManager () ... come prima.
ecv

2
Il tuo codice è stato un vero toccasana !! Stavo cercando di indirizzare sia il vecchio che il nuovo telefono e ho perso 3 giorni .. E la risposta è così semplice. Grazie
Devdatta Tengshe

22

Il mio approccio è molto vicino a quello di Garret Wilson (grazie, ti ho votato;)

Inoltre fornisce una compatibilità al ribasso con Android <3.

Ho appena riconosciuto che la mia soluzione è ancora più vicina a quella di Kevin Remo . È solo un po 'più pulito (in quanto non si basa sull'antipasto "attesa" ).

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();
    }
}

Per un esempio "reale" (ma più complesso) vedi NusicPreferencesActivity e NusicPreferencesFragment .


@SuppressLint("NewApi")- evitare - essere più precisi. L'hai eseguito per le API basse? Si getteràVerifyError
Mr_and_Mrs_D

Ho testato quanto sopra sull'emulatore con API livello 10, l'APK è stato creato utilizzando SDK versione 19. Quale versione SDK hai usato per la costruzione? A quale livello dell'API del dispositivo è stato eseguito? L'hai eseguito sull'emulatore o su un dispositivo fisico? Quando si è verificato esattamente l'errore? Se Ur crea con SDK <= 16, vedi questa risposta .
schnatterer,

Ti manca il punto - e aggiungi @Mr_and_Mrs_D se vuoi che io sia informato. Per il VE leggi qui: stackoverflow.com/questions/20271593/… . Lo @SuppressLint("NewApi")stile è semplicemente cattivo
Mr_and_Mrs_D

@M Bene, allora che ne dici di una proposta su come evitare @SuppressLint("NewApi")in questa particolare situazione?
schnatterer,

@TargetApi(Build.VERSION_CODES.HONEYCOMB)- non tutti gli avvertimenti per eventuali api :)
Mr_and_Mrs_D

6

Invece di eccezioni, basta usare:

if (Build.VERSION.SDK_INT >= 11)

e usare

@SuppressLint("NewApi")

per sopprimere gli avvisi.


1
perché non fa altro che crash: D
Ishtiaq

1
se è un crash ... quindi prova a prenderlo: D
gumuruh,

0

Invece di usare a PreferenceActivityper caricare direttamente le preferenze, usa un AppCompatActivityo equivalente che carica un PreferenceFragmentCompatche carica le tue preferenze. Fa parte della libreria di supporto (ora Android Jetpack) e fornisce compatibilità con API 14.

Nel tuo build.gradle, aggiungi una dipendenza per la libreria di supporto delle preferenze:

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

Nota: supponiamo che abbiate già creato le vostre preferenze XML.

Per la tua attività, crea una nuova classe di attività. Se stai usando temi materiali, dovresti estendere un AppCompatActivity, ma puoi essere flessibile con questo:

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()
        }
    }
}

Ora per la parte importante: crea un frammento che carica le tue preferenze da XML:

public class MyPreferencesFragment extends PreferenceFragmentCompat {

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

Per ulteriori informazioni, leggi i documenti per sviluppatori Android per PreferenceFragmentCompat.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.