Был ли PreferenceFragment намеренно исключен из пакета совместимости?

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

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

Приветствия

Джеймс

Ответ 1

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

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

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

Мое предположение - вопрос инженерного времени, но это всего лишь предположение.

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

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

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

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

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

См. выше.

Ответ 2

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

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 вместо "защищенного" является основным блокиратором. На самом деле не похоже, что есть какая-либо безопасность или действительно хорошая мотивация, чтобы сделать это, и это не очень удобно для модульного тестирования, но, о, хорошо... меньше набрав, я думаю...

EDIT v2: На самом деле это произошло, и это сработало. Это была определенная головная боль, чтобы заставить код работать с JAR совместимости API. Мне пришлось скопировать около 70% пакета com.android.preference из SDK в мое приложение, а затем бороться с типично средним качеством Java-кода на Android. Я использовал v14 SDK. Инженеру Goog было бы намного легче делать то, что я сделал, вопреки тому, что я слышал, некоторые ведущие инженеры Android говорят об этой теме.

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

Ответ 3

Основываясь на ответах 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.

Ответ 5

В августе 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 для стилей макетов, используемых для каждого типа предпочтений, без влияния на другие части вашей деятельности.

Ответ 6

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

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

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

И вы не можете обойти это, скрывая вашу реализацию в пакете android.preferences, потому что непубличные методы в API Android фактически исключены из SDK. С небольшим творческим потенциалом, включающим отражение и динамические прокси, вы все равно можете справиться с ними. Единственная альтернатива, как говорит Tenacious, заключается в том, чтобы развернуть весь пакет android.preference, включая как минимум 15 классов, 5 макетов и аналогичное количество элементов style.xml и attrs.xml.

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

Ответ 7

My app target - 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();
    }
}

Ответ 8

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

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