ISVALIDFRAGMENT Android API 19

quand j'essaie mon application avec Android KitKat j'ai une erreur dans PreferenceActivity.

les sous-classes de preference activity doivent supplanter isValidFragment (String) pour vérifier que la classe de Fragment est valide! COM.crbin1.labeltodo.ActivityPreference n'a pas vérifié si fragment com.crbin1.labeltodo.StockPreferenceFragment est valide

dans la documentation je trouve l'explication suivante

protégé booléen isValidFragment (chaîne fragmentName)

ajouté au niveau API 19

Les sous-classes

devraient remplacer cette méthode et vérifier que le fragment donné est un type valide à rattacher à cette activité. L'implémentation par défaut retourne true pour les applications construites pour android: targetSdkVersion plus ancienne que KITKAT. Pour les versions suivantes, il va jeter une exception.

je ne trouve aucun exemple de résoudre le problème.

49
demandé sur crbin1 2013-11-14 12:41:03

9 réponses

essayez ceci... c'est ainsi que nous vérifions la validité du fragment.

protected boolean isValidFragment(String fragmentName) {
  return StockPreferenceFragment.class.getName().equals(fragmentName);
}
65
répondu user2098324 2014-09-26 21:41:12

par pure curiosité, vous pouvez aussi le faire:

@Override
protected boolean isValidFragment(String fragmentName) {
    return MyPreferenceFragmentA.class.getName().equals(fragmentName)
            || MyPreferenceFragmentB.class.getName().equals(fragmentName)
            || // ... Finish with your last fragment.

;}
24
répondu davidcesarino 2014-09-26 21:40:09

j'ai trouvé que je pouvais prendre une copie de mes noms de fragments de ma ressource en-tête comme il a été chargé:

public class MyActivity extends PreferenceActivity
{
    private static List<String> fragments = new ArrayList<String>();

    @Override
    public void onBuildHeaders(List<Header> target)
    {
        loadHeadersFromResource(R.xml.headers,target);
        fragments.clear();
        for (Header header : target) {
            fragments.add(header.fragment);
        }
    }
...
    @Override
    protected boolean isValidFragment(String fragmentName)
    {
        return fragments.contains(fragmentName);
    }
}

de cette façon, je n'ai pas besoin de me rappeler de mettre à jour une liste de fragments enfouis dans le code si je veux les mettre à jour.

j'avais espéré utiliser getHeaders() et la liste existante des en-têtes directement, mais il semble que l'activité soit détruite après onBuildHeaders() et recréée avant isValidFragment() est appelé.

This peut-être parce que le Nexus 7 que je teste ne fait pas réellement des activités de préférence à deux volets. D'où la nécessité d'un membre de la liste statique.

20
répondu lane 2015-01-21 13:43:57

cette API a été ajoutée en raison d'une vulnérabilité nouvellement découverte. S'il vous plaît voir http://ibm.co/1bAA8kF ou http://ibm.co/IDm2Es

10 décembre 2013 "Nous avons récemment dévoilé une nouvelle vulnérabilité à L'équipe de sécurité Android. [...] Pour être plus précis, toute application qui étend la classe PreferenceActivity en utilisant une activité exportée est automatiquement vulnérable. Un patch a fourni dans Android KitKat. Si vous vous demandez pourquoi votre code est maintenant cassé, c'est en raison du patch Android KitKat qui nécessite des applications pour outrepasser la nouvelle méthode, PreferenceActivity.isValidFragment, qui a été ajouté au Cadre Android."- À partir du premier lien ci-dessus

18
répondu Roee Hay 2015-08-19 15:29:04

vérifié avec un appareil réel 4.4:

(1) si votre proguard.le fichier cfg a cette ligne ( que beaucoup définissent de toute façon ):

-keep public class com.fullpackage.MyPreferenceFragment

(2) que la mise en œuvre la plus efficace serait:

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class EditPreferencesHC extends PreferenceActivity {
...
   protected boolean isValidFragment (String fragmentName) {

     return "com.fullpackage.MyPreferenceFragment".equals(fragmentName);

   }
}
3
répondu auval 2017-05-23 11:46:52

Je ne suis pas sûr que l'implémentation de lane soit exempte des vulnérabilités discutées ici mais si c'est le cas, je pense qu'une meilleure solution serait d'éviter d'utiliser cette liste statique et de simplement faire ce qui suit:

 @Override
    protected boolean isValidFragment(String fragmentName)
    {
        ArrayList<Header> target = new ArrayList<>();
        loadHeadersFromResource(R.xml.pref_headers, target);
        for (Header h : target) {
            if (fragmentName.equals(h.fragment)) return true;
        }
        return false;
    }
3
répondu Ofek Ron 2017-05-23 12:17:52

c'est ma solution:

  • si u besoin de dynamique de reconstruction en-têtes
  • si u utiliser des suppléments pour démarrer l'activité de préférence - onBuildHeaders() approche ne fonctionnera pas! (avec des extras d'intention de départ ci-dessous-pourquoi ??? - simple car onbuild headers () n'est jamais appelé):

    intention.putExtra (Préférenceactivité.EXTRA_SHOW_FRAGMEN, Fragment.classe.getName()); Intention.putExtra (Préférenceactivité.EXTRA_NO_HEADERS, true);

C'est la classe exemple:

/**
 * Preference Header for showing settings and add view as two panels for tablets
 * for ActionBar we need override onCreate and setContentView
 */
public class SettingsPreferenceActivity extends PreferenceActivity {

    /** valid fragment list declaration */
    private List<String> validFragmentList;

    /** some example irrelevant class for holding user session  */
    SessionManager _sessionManager;

    @Override
    public void onBuildHeaders(List<Header> target) {
        /** load header from res */
        loadHeadersFromResource(getValidResId(), target);
    }

    /**
     * this API method was added due to a newly discovered vulnerability.
     */
    @Override
    protected boolean isValidFragment(String fragmentName) {
        List<Header> headers = new ArrayList<>();
        /** fill fragments list */
        tryObtainValidFragmentList(getValidResId(), headers);
        /** check  id valid */
        return validFragmentList.contains(fragmentName);
    }

    /** try fill list of valid fragments */
    private void tryObtainValidFragmentList(int resourceId, List<Header> target) {  
        /** check for null */
        if(validFragmentList==null) {
            /** init */
            validFragmentList = new ArrayList();
        } else {
            /** clear */
            validFragmentList.clear();
        }
        /** load headers to list */
        loadHeadersFromResource(resourceId, target);
        /** set headers class names to list */
        for (Header header : target) {
            /** fill */
            validFragmentList.add(header.fragment);
        }
    }

    /** obtain valid res id to build headers */
    private int getValidResId() {
        /** get session manager */
        _sessionManager = SessionManager.getInstance();
        /** check if user is authorized */
        if (_sessionManager.getCurrentUser().getWebPart().isAuthorized()) {
            /** if is return full preferences header */
            return R.xml.settings_preferences_header_logged_in;
        } else {
            /** else return short header */
            return R.xml.settings_preferences_header_logged_out;
        }
    }
}
0
répondu ceph3us 2016-01-14 18:27:03

Voici mes headers_preferences.fichier xml:

<?xml version="1.0" encoding="utf-8"?>  
<preference-headers  
xmlns:android="http://schemas.android.com/apk/res/android">  

    <header  

        android:fragment="com.gammazero.signalrocket.AppPreferencesFragment$Prefs1Fragment"  
        android:title="Change Your Name" />  

    <header  
        android:fragment="com.gammazero.signalrocket.AppPreferencesFragment$Prefs2Fragment"  
        android:title="Change Your Group''s Name" />  

    <header  
        android:fragment="com.gammazero.signalrocket.AppPreferencesFragment$Prefs3Fragment"  
        android:title="Change Map View" />  

</preference-headers>  

dans mon activité préférée où le code isValidFragment se produit, je l'ai juste tourné sur sa tête:

@Override
protected boolean isValidFragment(String fragmentName)
{
  //  return AppPreferencesFragment.class.getName().contains(fragmentName);
    return fragmentName.contains (AppPreferencesFragment.class.getName());
}

tant que j'utilise la chaîne AppPreferencesFragment au début de tous les noms de mes fragments, ils valident parfaitement.

0
répondu James Schrumpf 2016-09-21 01:09:44

ma solution (au lieu de créer ArrayList de classe) puisque les fragments qui sont chargés suppose être sous-classe de fragment de préférence.cours effectuer ce contrôle dans le Méthode @OverRide

@Override
protected boolean isValidFragment(String fragmentName) {
    try {
        Class cls = Class.forName(fragmentName);
        return (cls.getSuperclass().equals(PreferenceFragment.class));
                                  // true if superclass is PreferenceFragmnet
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
    return false;
}
0
répondu ItzikH 2018-04-15 21:01:05