isValidFragment Android API 19


Cuando pruebo mi aplicación con Android KitKat tengo un error en PreferenceActivity.

Las subclases de PreferenceActivity deben anular isValidFragment(Cadena) para verificar que la clase Fragment es válida! com.crbin1.labeltodo.ActivityPreference no ha comprobado si fragment com.crbin1.labeltodo.StockPreferenceFragment is valid

En la documentación encuentro la siguiente explicación

IsValidFragment booleano protegido (String fragmentName)

Añadido en el nivel de API 19

Las subclases deben sobrescribir este método y verificar que el fragmento dado es un tipo válido que se adjuntará a esta actividad. La implementación predeterminada devuelve true para aplicaciones creadas para Android: targetSdkVersion anteriores a KITKAT. Para versiones posteriores, lanzará una excepción.

No encuentro ningún ejemplo para resolver el problema.

Author: crbin1, 2013-11-14

9 answers

Prueba esto... así es como comprobamos la validez del fragmento.

protected boolean isValidFragment(String fragmentName) {
  return StockPreferenceFragment.class.getName().equals(fragmentName);
}
 65
Author: user2098324,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-26 21:41:12

Por pura curiosidad, también puedes hacer esto:

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

;}
 24
Author: davidcesarino,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-26 21:40:09

Descubrí que podía tomar una copia de los nombres de mis fragmentos de mi recurso de encabezado a medida que se cargaba:

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 esta manera no necesito recordar actualizar una lista de fragmentos enterrados en el código si quiero actualizarlos.

Esperaba usar getHeaders() y la lista existente de encabezados directamente, pero parece que la actividad se destruye después de onBuildHeaders() y se vuelve a crear antes de que se llame isValidFragment().

Esto puede deberse a que el Nexus 7 en el que estoy probando no tiene preferencia de dos paneles actividad. De ahí la necesidad del miembro estático de la lista también.

 20
Author: lane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-21 13:43:57

Esta API se agregó debido a una vulnerabilidad recientemente descubierta. Por favor, consulte http://ibm.co/1bAA8kF o http://ibm.co/IDm2Es

10 de diciembre de 2013 "Recientemente hemos revelado una nueva vulnerabilidad para el Equipo de Seguridad de Android. [...] Para ser más precisos, cualquier Aplicación que extendiera la clase PreferenceActivity usando una actividad exportada era automáticamente vulnerable. Se ha proporcionado un parche en Android KitKat. Si te preguntas por qué tu código ahora está roto, se debe al parche KitKat de Android que requiere que las aplicaciones anulen el nuevo método, PreferenceActivity.isValidFragment, que se ha añadido al framework de Android."From Desde el primer enlace anterior

 18
Author: Roee Hay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-19 15:29:04

Verificado con un dispositivo 4.4 real:

(1) si su proguard.el archivo cfg tiene esta línea ( que muchos definen de todos modos):

-keep public class com.fullpackage.MyPreferenceFragment

(2) que la aplicación más eficiente sería:

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

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

   }
}
 3
Author: auval,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:46:52

No estoy seguro de si la implementación de lane está libre de las vulnerabilidades discutidas aquí pero si lo está, entonces creo que una mejor solución sería evitar usar esa lista estática y simplemente hacer lo siguiente :

 @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
Author: Ofek Ron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:17:52

Esta es mi solución:

  • si u necesita encabezados de reconstrucción dinámica
  • Si u usa extras para iniciar la actividad de preferencias-el enfoque onBuildHeaders () fallará! (con los siguientes extras de intención de inicio - ¿por qué ??? - simple porque onBuildHeaders () nunca se llama):

    Intención.putExtra (PreferenceActivity.EXTRA_SHOW_FRAGMEN, Fragment.clase.getName()); Intención.putExtra (PreferenceActivity.EXTRA_NO_HEADERS, true);

Esta es una clase de ejemplo:

/**
 * 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
Author: ceph3us,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-14 18:27:03

Aquí están mis headers_preferences.archivo 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>  

En mi PreferencesActivity donde ocurre el código isValidFragment, simplemente lo giré de cabeza:

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

Mientras use la cadena AppPreferencesFragment al comienzo de todos los nombres de mis fragmentos, todos se validan bien.

 0
Author: James Schrumpf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-21 01:09:44

Mi solución (en lugar de crear ArrayList de clase) ya que los fragmentos que se cargan suponen ser subclase de PreferenceFragment.clase ejecutar esta comprobación en el @OverRide método

@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
Author: ItzikH,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-15 21:01:05