web-dev-qa-db-fra.com

PreferenceActivity Android 4.0 et versions antérieures

En essayant les différentes activités de préférence dans ApiDemos pour Android 4.0, je vois dans le code que certaines méthodes sont déconseillées dans PreferencesFromCode.Java, par exemple.

Donc ma question est: si j'utilise PreferenceFragment, cela fonctionnera-t-il pour toutes les versions ou seulement 3.0 ou 4.0 et plus?

Si oui, que dois-je utiliser qui fonctionne également pour les versions 2.2 et 2.3?

36
just_user

PreferenceFragment ne fonctionnera pas sur 2.2 et 2.3 (uniquement API niveau 11 et supérieur). Si vous souhaitez offrir la meilleure expérience utilisateur tout en prenant en charge les anciennes versions Android Android, la meilleure pratique semble être d'implémenter deux classes PreferenceActivity et de décider au moment de l'exécution laquelle Cependant, cette méthode inclut toujours l'appel aux API obsolètes, mais vous ne pouvez pas l'éviter.

Ainsi, par exemple, vous avez un preference_headers.xml:

<preference-headers xmlns:Android="http://schemas.Android.com/apk/res/Android" > 
    <header Android:fragment="your.package.PrefsFragment" 
        Android:title="...">
        <extra Android:name="resource" Android:value="preferences" />
    </header>
</preference-headers>

et une norme preferences.xml (qui n'a pas beaucoup changé depuis les niveaux d'API inférieurs):

<PreferenceScreen xmlns:Android="http://schemas.Android.com/apk/res/Android" Android:title="...">
    ...
</PreferenceScreen>

Ensuite, vous avez besoin d'une implémentation de PreferenceFragment:

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

Et enfin, vous avez besoin de deux implémentations de PreferenceActivity, pour les niveaux d'API supportant ou non PreferenceFragments:

public class PreferencesActivity extends PreferenceActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);
        addPreferencesFromResource(R.xml.other);
    }
}

et:

public class OtherPreferencesActivity extends PreferenceActivity {
    @Override
    public void onBuildHeaders(List<Header> target) {
        loadHeadersFromResource(R.xml.preference_headers, target);
    }
}

Au moment où vous souhaitez afficher l'écran de préférence à l'utilisateur, vous décidez lequel commencer:

if (Build.VERSION.SDK_INT < 11) {
    startActivity(new Intent(this, PreferencesActivity.class));
} else {
    startActivity(new Intent(this, OtherPreferencesActivity.class));
}

Donc, fondamentalement, vous avez un fichier xml par fragment, vous chargez chacun de ces fichiers xml manuellement pour les niveaux d'API <11, et les deux activités utilisent les mêmes préférences.

59
Leo

@Mef Votre réponse peut être encore plus simplifiée afin que vous n'ayez pas besoin à la fois de PreferencesActivity et OtherPreferencesActivity (avoir 2 PrefsActivities est un PITA).

J'ai trouvé que vous pouvez mettre la méthode onBuildHeaders () dans votre PreferencesActivity et aucune erreur ne sera levée par les versions Android avant la v11). sur 2.3.6, mais l'a fait sur Android 1.6. Après quelques bricolages cependant, j'ai trouvé que le code suivant fonctionnera dans toutes les versions de sorte qu'une seule activité est requise (ce qui simplifie considérablement les choses).

public class PreferencesActivity extends PreferenceActivity {
    protected Method mLoadHeaders = null;
    protected Method mHasHeaders = null;

    /**
     * Checks to see if using new v11+ way of handling PrefFragments.
     * @return Returns false pre-v11, else checks to see if using headers.
     */
    public boolean isNewV11Prefs() {
        if (mHasHeaders!=null && mLoadHeaders!=null) {
            try {
                return (Boolean)mHasHeaders.invoke(this);
            } catch (IllegalArgumentException e) {
            } catch (IllegalAccessException e) {
            } catch (InvocationTargetException e) {
            }
        }
        return false;
    }

    @Override
    public void onCreate(Bundle aSavedState) {
        //onBuildHeaders() will be called during super.onCreate()
        try {
            mLoadHeaders = getClass().getMethod("loadHeadersFromResource", int.class, List.class );
            mHasHeaders = getClass().getMethod("hasHeaders");
        } catch (NoSuchMethodException e) {
        }
        super.onCreate(aSavedState);
        if (!isNewV11Prefs()) {
            addPreferencesFromResource(R.xml.preferences);
            addPreferencesFromResource(R.xml.other);
        }
    }

    @Override
    public void onBuildHeaders(List<Header> aTarget) {
        try {
            mLoadHeaders.invoke(this,new Object[]{R.xml.pref_headers,aTarget});
        } catch (IllegalArgumentException e) {
        } catch (IllegalAccessException e) {
        } catch (InvocationTargetException e) {
        }   
    }
}

De cette façon, vous n'avez besoin que d'une activité, d'une entrée dans votre fichier AndroidManifest.xml et d'une ligne lorsque vous invoquez vos préférences:

startActivity(new Intent(this, PreferencesActivity.class);

MISE À JOUR d'octobre 2013: Eclipse/Lint vous avertira de l'utilisation de la méthode obsolète, mais ignorera simplement l'avertissement. Nous n'utilisons la méthode que lorsque nous le devons, c'est-à-dire chaque fois que nous n'avons pas de préférences de style v11 + et que nous devons l'utiliser, ce qui est OK. N'ayez pas peur du code obsolète lorsque vous l'avez expliqué, Android ne supprimera pas les méthodes obsolètes de sitôt. Si cela se produisait, vous n'aurez même plus besoin de cette classe car vous serait obligé de cibler uniquement les appareils les plus récents. Le mécanisme obsolète est là pour vous avertir qu'il existe un meilleur moyen de gérer quelque chose sur la dernière version de l'API, mais une fois que vous l'avez pris en compte, vous pouvez ignorer l'avertissement en toute sécurité. La suppression de tous les appels à des méthodes obsolètes ne ferait que forcer votre code à s'exécuter uniquement sur des appareils plus récents, éliminant ainsi la nécessité d'une compatibilité descendante.

18
Uncle Code Monkey

Il y a un newish lib qui pourrait aider.

UnifiedPreference est une bibliothèque pour travailler avec toutes les versions du package de préférences Android d'API v4 et plus).

6
scottyab

Le problème avec les réponses précédentes est qu'il empilera toutes les préférences sur un seul écran sur les appareils pré-Honecomb (en raison de plusieurs appels de addPreferenceFromResource()).

Si vous avez besoin du premier écran en tant que liste, puis de l'écran des préférences (comme l'utilisation des en-têtes de préférence), vous devez utiliser Guide officiel des préférences compatibles

5
David Vávra

Je voulais souligner que si vous commencez par http://developer.Android.com/guide/topics/ui/settings.html#PreferenceHeaders et que vous descendez jusqu'à la section "Supporter les anciens versions avec en-têtes de préférence ", il sera plus logique. Le guide est très utile et fonctionne bien. Voici un exemple explicite suivant leur guide:

Alors commencez avec le fichier preference_header_legacy.xml pour les systèmes Android avant HoneyComb

<PreferenceScreen xmlns:Android="http://schemas.Android.com/apk/res/Android">
<Preference 
    Android:title="OLD Test Title"
    Android:summary="OLD Test Summary"  >
    <intent 
        Android:targetPackage="example.package"
        Android:targetClass="example.package.SettingsActivity"
        Android:action="example.package.PREFS_ONE" />
</Preference>

Créer ensuite un fichier preference_header.xml pour les systèmes Android avec HoneyComb +

<preference-headers xmlns:Android="http://schemas.Android.com/apk/res/Android">
<header 
    Android:fragment="example.package.SettingsFragmentOne"
    Android:title="NEW Test Title"
    Android:summary="NEW Test Summary" />
</preference-headers>

Créez ensuite un preferences.xml fichier pour conserver vos préférences ...

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:Android="http://schemas.Android.com/apk/res/Android" >
        <CheckBoxPreference
        Android:key="pref_key_auto_delete"
        Android:summary="@string/pref_summary_auto_delete"
        Android:title="@string/pref_title_auto_delete"
        Android:defaultValue="false" />
</PreferenceScreen>

Créez ensuite le fichier SettingsActivity.Java

package example.project;
import Java.util.List;
import Android.annotation.SuppressLint;
import Android.os.Build;
import Android.os.Bundle;
import Android.preference.PreferenceActivity;

public class SettingsActivity extends PreferenceActivity{
final static String ACTION_PREFS_ONE = "example.package.PREFS_ONE";

@SuppressWarnings("deprecation")
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    String action = getIntent().getAction();
    if (action != null && action.equals(ACTION_PREFS_ONE)) {
        addPreferencesFromResource(R.xml.preferences);
    }
    else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
        // Load the legacy preferences headers
        addPreferencesFromResource(R.xml.preference_header_legacy);
    }
}

@SuppressLint("NewApi")
@Override
public void onBuildHeaders(List<Header> target) {
    loadHeadersFromResource(R.xml.preference_header, target);
}
}

Créez ensuite la classe SettingsFragmentOne.Java

package example.project;
import Android.annotation.SuppressLint;
import Android.os.Bundle;
import Android.preference.PreferenceFragment;

@SuppressLint("NewApi")
public class SettingsFragmentOne extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    addPreferencesFromResource(R.xml.preferences);
}
}

AndroidManifest.xml, a ajouté ce bloc entre mes <application> Mots clés

<activity 
   Android:label="@string/app_name"
   Android:name="example.package.SettingsActivity"
   Android:exported="true">
</activity>

et enfin, pour le <wallpaper> tag ...

<wallpaper xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:description="@string/description"
Android:thumbnail="@drawable/ic_thumbnail"
Android:settingsActivity="example.package.SettingsActivity"
/>
2
EnzoAtari

J'utilise cette bibliothèque , qui a un AAR dans mavenCentral afin que vous puissiez facilement l'inclure si vous utilisez Gradle.

compile 'com.github.machinarius:preferencefragment:0.1.1'

1
theblang