Был ли PreferenceFragment преднамеренно исключен из пакета совместимости? - PullRequest
153 голосов
/ 31 марта 2011

Я хочу написать настройки, которые можно применить как к устройствам 3.0, так и к версиям до 3.0.Обнаружив, что PreferenceActivity содержит устаревшие методы (хотя они используются в прилагаемом примере кода), я посмотрел на PreferenceFragement и пакет совместимости, чтобы решить мои проблемы.

Похоже, что PreferenceFragmentнет в пакете совместимости.Кто-нибудь может сказать мне, было ли это преднамеренным?Если да, могу ли я легко настроить таргетинг на ряд устройств (то есть <3.0 и> = 3.0) или мне придется прыгать через обручи?Если это не было преднамеренно исключено, можем ли мы ожидать новый выпуск пакета совместимости?Или есть другой обходной путь, который безопасно использовать?

Приветствия

Джеймс

Ответы [ 8 ]

90 голосов
/ 31 марта 2011

Обнаружение того, что PreferenceActivity содержит устаревшие методы (хотя они используются в прилагаемом примере кода)

Начиная с Android 3.0 устаревшие методы устарели.Они прекрасно работают на всех версиях Android, но нацелено на использование PreferenceFragment на Android 3.0 и выше.

Может кто-нибудь сказать мне, было ли это намеренно?

Полагаю, это вопрос инженерного времени, но это всего лишь предположение.

Если это так, могу ли я легко настроить таргетинг на ряд устройств (т.е. <3.0 и> = 3.0) или мне придется прыгать через обручи?

Я считаю этобыть сделано "легко".Имеют две отдельные реализации PreferenceActivity, одна с использованием заголовков предпочтений и PreferenceFragments, другая с использованием оригинального подхода.Выберите правильный в нужной точке (например, когда пользователь нажимает на пункт меню параметров). Вот пример проекта , демонстрирующий это.Или иметь один PreferenceActivity, который обрабатывает оба случая, как в этом примере проекта .

Если он не был преднамеренно исключен, можем ли мы ожидать нового выпускапакет совместимости?

Вы узнаете, когда остальные из нас узнают, то есть, когда и когда он отправит.

Или есть другой обходной путь, которыйбезопасно использовать?

См. выше.

21 голосов
/ 11 января 2012

Тонкий смысл ответа от @CommonsWare заключается в том, что ваше приложение должно выбирать между API совместимости или встроенным API фрагментов (начиная с SDK 11 или около того). Фактически это то, что сделала «легкая» рекомендация. Другими словами, если вы хотите использовать PreferenceFragment, ваше приложение должно использовать встроенный API-фрагмент и работать с устаревшими методами в PreferenceActivity. И наоборот, если важно, чтобы ваше приложение использовало компат. API вы столкнетесь с отсутствием класса PreferenceFragment вообще. Таким образом, нацеливание на устройства не является проблемой, но скачкообразное изменение происходит, когда вам нужно выбрать тот или иной API и, таким образом, представить свой дизайн непредвиденным обходным путям. Мне нужен компат. API, поэтому я собираюсь создать свой собственный класс PreferenceFragment и посмотреть, как это работает. В худшем случае я просто создам нормальный (фрагмент) макет и вручную привяжу компоненты представления к sharedprefs ... тьфу.

EDIT: После попытки взглянуть на код http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/preference/PreferenceFragment.java?av=h - создание собственного PreferenceFragment не произойдет. Похоже, что в PreferenceManager либеральное использование package-private вместо «protected» является основным препятствием. Это действительно не похоже на то, что есть какая-то безопасность или действительно хорошая мотивация, чтобы сделать это, и это не очень хорошо для юнит-тестирования, ну да ладно ... меньше печатать, я думаю ...

РЕДАКТИРОВАТЬ v2: На самом деле это случилось, и это сработало. Определенно было головной болью заставить код работать с JAR API совместимости. Мне пришлось скопировать около 70% пакета com.android.preference из SDK в мое приложение, а затем бороться с типично посредственным Java-кодом в Android. Я использовал v14 SDK. Для инженера Goog было бы намного проще сделать то, что я сделал, вопреки тому, что я слышал от ведущих разработчиков Android по этому поводу.

КСТАТИ - я сказал "таргетинг на устройства не проблема"? Это полностью ... если вы используете com.android.preference, вы не сможете обменяться с API совместимости без серьезного рефакторинга. Веселый журнал!

16 голосов
/ 05 июля 2012

Опираясь на ответ CommonsWare и наблюдения Tenacious, я разработал единственное решение класса-потомка, способное нацеливаться на все текущие версии Android API с минимальными усилиями и без дублирования кода или ресурсов. Пожалуйста, смотрите мой ответ на соответствующий вопрос здесь: PreferenceActivity для Android 4.0 и более ранних версий

или в моем блоге: http://www.blackmoonit.com/2012/07/all_api_prefsactivity/

Протестировано на двух планшетах под управлением 4.0.3 и 4.0.4, а также на телефоне под управлением 4.0.4 и 2.3.3, а также на эмуляторе под управлением 1.6.

10 голосов
/ 01 сентября 2015

В августе 2015 года Google выпустила новую библиотеку поддержки предпочтений v7 .

Теперь вы можете использовать PreferenceFragmentCompat с любым Activity или AppCompatActivity

public static class PrefsFragment extends PreferenceFragmentCompat {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Load the preferences from an XML resource
        addPreferencesFromResource(R.xml.preferences);
    }
}

Вы должны установить preferenceTheme в своей теме:

<style name="AppTheme" parent="@style/Theme.AppCompat.Light">
  ...
  <item name="preferenceTheme">@style/PreferenceThemeOverlay</item>
</style>

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

10 голосов
/ 09 мая 2014

См. PreferenceFragment-Compat от Machinarius.С Gradle было легко заскочить, и я забыл, что это даже там.

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

Важное обновление: Последняя версия изv7 support library теперь имеет собственный PreferenceFragmentCompat .

7 голосов
/ 01 мая 2013

Ответ Tenacious правильный, но вот еще некоторые подробности.

Причина, по которой вы не можете «создать нормальный макет и связать компоненты представления с sharedprefs вручную», заключается в том, что в некоторых неожиданных упущенияхAPI android.preferences.PreferenceActivity и PreferenceFragment оба имеют доступ к критическим непубличным методам PreferenceManager, без которых вы не сможете реализовать собственный интерфейс предпочтений.

В частности, для построения иерархии предпочтений из XML-файла, который необходимо использоватьPreferenceManager, но все конструкторы PreferenceManager являются пакетными или скрытыми.Метод присоединения слушателей Preference onClick к вашей активности также является частным для пакета.

И вы не можете обойти это, хитро поместив свою реализацию в пакет android.preferences, потому что непубличные методы в AndroidAPI фактически исключены из SDK.Приложив немного креатива, включая рефлексию и динамические прокси, вы все равно можете их получить.Единственная альтернатива, как говорит Тенасид, - это разветвить весь пакет android.preference, включая как минимум 15 классов, 5 макетов и аналогичное количество элементов style.xml и attrs.xml.

Итак, чтобы ответитьИсходный вопрос, причина, по которой Google не включил PreferenceFragment в пакет совместимости, заключается в том, что у них была бы точно такая же сложность, как и у Tenacious и у меня.Даже Google не может вернуться назад во времени и сделать эти методы общедоступными на старых платформах (хотя я надеюсь, что они сделают это в будущих выпусках).

2 голосов
/ 20 февраля 2014

Мне нужно было интегрировать настройки в дизайн приложения и поддерживать 2.3 Android. Поэтому мне все еще нужен был PreferencesFragment.

После некоторого поиска я нашел android-support-v4-preferencefragment lib. Эта библиотека экономит много времени на копирование и рефакторинг оригинального PreferencesFragment, как сказал Tenacious. Работает нормально, и пользователи наслаждаются настройками.

2 голосов
/ 17 августа 2013

Моя цель приложения - API +14, но из-за использования библиотеки поддержки для какой-то необычной навигации я не смог использовать android.app.Fragment и пришлось использовать android.support.v4.app.Fragment, но мне также нужно было иметь PreferenceFragment на месте без большие изменения в коде позади.

Итак, мое простое исправление - иметь оба мира поддержки библиотеки и PreferenceFragment:

private android.support.v4.app.Fragment fragment;
private android.app.Fragment nativeFragment = null;

private void selectItem(int position) {
    fragment = null;
    boolean useNativeFragment = false;
    switch (position) {
    case 0:
        fragment = new SampleSupprtFragment1();
        break;
    case 1:
        fragment = new SampleSupprtFragment2();
        break;
    case 2:
        nativeFragment = new SettingsFragment();
        useNativeFragment = true;
        break;
    }
    if (useNativeFragment) {
        android.app.FragmentManager fragmentManager = getFragmentManager();
        fragmentManager.beginTransaction()
            .replace(R.id.content_frame, nativeFragment).commit();
    } else {
        if (nativeFragment != null) {
            getFragmentManager().beginTransaction().remove(nativeFragment)
                .commit();
            nativeFragment = null;
        }
        FragmentManager fragmentManager = getSupportFragmentManager();
        fragmentManager.beginTransaction()
            .replace(R.id.content_frame, fragment).commit();
    }
}
...