Подтвердить что ты не робот

IsValidFragment Android API 19

Когда я пытаюсь выполнить свое приложение с Android KitKat, у меня есть ошибка в PreferenceActivity.

Подклассы PreferenceActivity должны переопределить isValidFragment (String), чтобы убедиться, что класс Fragment действителен! com.crbin1.labeltodo.ActivityPreference не проверял, действительно ли фрагмент com.crbin1.labeltodo.StockPreferenceFragment действителен

В документации я найду следующее объяснение

protected boolean isValidFragment (String имя_файла)

Добавлен в уровень API 19

Подклассы должны переопределить этот метод и убедиться, что данный фрагмент является допустимым типом, который должен быть присоединен к этому действию. Реализация по умолчанию возвращает true для приложений, созданных для android: targetSdkVersion старше KITKAT. Для более поздних версий он генерирует исключение.

Я не нашел примера для решения проблемы.

4b9b3361

Ответ 1

Попробуйте это... так мы проверяем правильность фрагмента.

protected boolean isValidFragment(String fragmentName) {
  return StockPreferenceFragment.class.getName().equals(fragmentName);
}

Ответ 2

Из чистого любопытства вы также можете сделать это:

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

;}

Ответ 3

Я обнаружил, что могу захватить копию моих имен фрагментов из моего ресурса заголовка, когда он был загружен:

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

Таким образом, мне не нужно забывать обновлять список фрагментов, закодированных в коде, если я хочу их обновить.

Я надеялся использовать getHeaders() и существующий список заголовков напрямую, но кажется, что действие уничтожается после onBuildHeaders() и воссоздается до вызова isValidFragment().

Возможно, это связано с тем, что Nexus 7, на котором я тестирую, фактически не выполняет действия с двумя панелями. Отсюда и потребность в статическом элементе списка.

Ответ 4

Этот API был добавлен из-за недавно обнаруженной уязвимости. См. http://ibm.co/1bAA8kF или http://ibm.co/IDm2Es

10 декабря 2013 г. "Недавно мы раскрыли новую уязвимость для группы безопасности Android. [...] Чтобы быть более точным, любое приложение, которое расширило класс PreferenceActivity с помощью экспортированной активности, было автоматически уязвимо. Патч был предоставлен в Android KitKat. почему ваш код сейчас сломан, это связано с патчем Android KitKat, который требует, чтобы приложения переопределяли новый метод PreferenceActivity.isValidFragment, который был добавлен в Android Framework". - Из первой ссылки выше

Ответ 5

Проверено с помощью устройства с 4.4:

(1), если ваш файл proguard.cfg имеет эту строку (которую многие определяют в любом случае):

-keep public class com.fullpackage.MyPreferenceFragment

(2), чем наиболее эффективная реализация:

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

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

   }
}

Ответ 6

Я не уверен, что в случае реализации в полосе не будет обсуждаемых уязвимостей здесь, но если это так, то я думаю, что лучшим решением было бы избежать использования этого статического списка и просто выполните следующее:

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

Ответ 7

это мое решение:

  • Если вам нужны динамические заголовки перекомпоновки
  • Если вы используете дополнительные функции для запуска активности предпочтений - метод onBuildHeaders() завершится неудачно! (с нижеприведенными дополнениями для запуска - почему??? - просто потому, что onBuildHeaders() никогда не вызывается):

    Intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMEN, Fragment.class.getName()); Intent.putExtra(PreferenceActivity.EXTRA_NO_HEADERS, true);

Это пример класса:

/**
 * 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;
        }
    }
}

Ответ 8

Вот мой файл headers_preferences.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' Name" />  

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

</preference-headers>  

В моей PreferencesActivity, где происходит код isValidFragment, я просто повернул его на голову:

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

Пока я использую строку AppPreferencesFragment в начале всех имен моих фрагментов, все они проверяются просто отлично.