Чи було навмисно виключено PreferenceFragment з пакету сумісності?


153

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

Схоже, цього PreferenceFragmentнемає в пакеті сумісності. Хтось може мені сказати, чи це було навмисно? Якщо так, чи можу я легко націлити цілу низку пристроїв (тобто <3.0 та> = 3.0) чи мені доведеться стрибати через обручі? Якщо це не було навмисно виключено, чи можна очікувати нового випуску пакета сумісності? Або є інше рішення, безпечне у використанні?

Ура

Джеймс


1
Це мій підхід до вирішення проблеми: stackoverflow.com/questions/14076073/…
ecv

Хтось зробив третю сторону, PreferenceFragmentяку ви забудете, навіть там є. Дивіться мою відповідь .
theblang

Кріс Бейнс вирішує це у коментарі до свого блогу . Він сказав, що причина в тому,"Because most of Preferences' implementation is hidden, therefore impossible to backport without lots of hackery."
theblang

Дивіться мою оновлену відповідь . PreferenceFragmentCompatнещодавно додано до бібліотеки підтримки.
theblang

Відповіді:


90

Виявлення, що PreferenceActivity містить застарілі методи (хоча вони використовуються в супровідному прикладі коду)

Застарілі методи застаріли в Android 3.0. Вони ідеально підходять для всіх версій Android, але напрямок - використовувати PreferenceFragmentна Android 3.0 і вище.

Хтось може мені сказати, чи це було навмисно?

Я здогадуюсь, це питання інженерного часу, але це лише здогадка.

Якщо так, чи можу я легко націлити цілу низку пристроїв (тобто <3.0 та> = 3.0) чи мені доведеться стрибати через обручі?

Вважаю це зробити "легко". Мають дві окремі PreferenceActivityреалізації, одна використовує заголовки переваг PreferenceFragments, а друга використовує оригінальний підхід. Виберіть потрібний у потрібній точці (наприклад, коли користувач натисне на пункт меню параметрів). Ось зразок проекту, що демонструє це. Або мати єдиний, PreferenceActivityякий обробляє обидва випадки, як у цьому зразковому проекті .

Якщо це не було навмисно виключено, чи можна очікувати нового випуску пакета сумісності?

Ви дізнаєтесь, коли решту з нас дізнаються, що означає, якщо і коли вона відправляється.

Або є інше рішення, безпечне у використанні?

Дивись вище.


Ура! Я бачив, що ви коментували це в декількох місцях (гурт Google android і ваш блог), але хотіли остаточної відповіді (наскільки можна отримати, враховуючи обставини).
Джеймс

@James: Так, руб буде знаходитися у визначенні переваг XML, отримуючи щось, що буде добре працювати, як фрагменти, а також об'єднуватися разом, оскільки я не впевнений, що <include>працює з перевагою XML. BTW, якщо ви передплатник, оновлення книги з посиланням на цей проект було оголошено хвилин тому.
CommonsWare

7
Вибачте, але я не дуже впевнений, який момент ви тут намагаєтеся зробити. Ви взагалі нічого не відповідаєте, просто коментуєте / здогадуєтесь / посилаєтесь на неактуальні зовнішні посилання, які не мають нічого спільного з проблемою. Питання полягає в тому, чи був пропуск навмисним чи ні, без версії сумісності PreferenceFragment немає засобів для розширення PreferenceActivity у описаному вами способі, тому що якщо PreferenceFragment не існує, то ні getSupportFragmentManager (), ні будь-який інший метод потрібно використовувати фрагменти в першу чергу.
Джастін Бусер

8
@JustinBuser: "Питання в тому, чи був упущення умисним чи ні" - єдині люди, які можуть відповісти на цю роботу в Google. Ви можете влаштуватися на роботу в Google, щоб спробувати дізнатися. "немає способу розширення PreferenceActivity так, як ви описали" - ви можете завантажити код, з яким я пов’язаний.
CommonsWare

9
@JustinBuser Для запису Марк відповів на моє запитання. Це видно з того, що я приймаю його відповідь.
Джеймс

21

Тонкий сенс відповіді від @CommonsWare полягає в тому, що - ваша програма повинна вибирати між сумісністю API або вбудованим фрагментом API (починаючи з SDK 11 або більше). Насправді саме це зробила рекомендація "легко". Іншими словами, якщо ви хочете використовувати PreferenceFragment, вашому додатку потрібно використовувати вбудований API фрагмента та мати справу зі застарілими методами на PreferenceActivity. І навпаки, якщо важливо, щоб ваш додаток використовував компат. API, з яким ви зіткнетесь, взагалі не матиме клас PreferenceFragment. Таким чином, націлювання на пристрої не є проблемою, але стрибки з обручем трапляються, коли вам доведеться вибрати той чи інший API і таким чином подати свою конструкцію на непередбачені обходи. Мені потрібен компат. API, тому я збираюся створити власний клас PreferenceFragment і подивитися, як це працює. У гіршому випадку я '

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: насправді це сталося, і воно спрацювало. Однозначно головний біль змусив код працювати з API сумісності JAR. Мені довелося скопіювати близько 70% пакету com.android.preference з SDK в моє додаток, а потім боротися з типово середньоякісним кодом Java в Android. Я використав v14 SDK. Інженеру Goog було б набагато простіше робити те, що я робив, всупереч тому, що я чув, як деякі ведучі Android-інженерів говорять про цю тему.

BTW - я сказав: "націлювання на пристрої не проблема"? Це повністю ... якщо ви використовуєте com.android.preference, ви не зможете заміняти API сумісності без капітального рефакторингу. Веселий журнал!


Дозвольте бути більш прямим. Якщо все, що вам цікаво, орієнтується на Honeycomb та вище (у яких частка частки ринку?), Тоді голосуйте за відповідь від @Commonsware! Якщо ви дбаєте про більшість Android-пристроїв на ринку сьогодні, ви повинні прочитати мою відповідь.
Наполегливий

4
Ви б готові поділитися тим, як це зробили? Я зіткнувся з точно такою самою проблемою, лише моя PreferenceActivity повинна використовувати навантажувачі, тому я повинен використовувати бібліотеку сумісності.
Каракурі

3
@Tenacious Мені подобається ваше розслідування - молодець. Однак я вважаю, що хтось повинен встановити запис прямо на ваш перший коментар там - код Commonsware буде працювати на пристроях перед і після HC - спробуйте спочатку, перш ніж робити такі коментарі. Те, що вам потрібно усвідомити, - це пізня прив’язка, яка використовується під час виконання для підтримки попередніх пристроїв. Перевірка версій під час виконання роботи забезпечує підтримку обох сімей ОС - це загальна модель Android (не одна мені подобається - але така, що важливо розробникам Android вивчити та ознайомитись) ... Тож майбутнім читачам - не Не відхиляю жодного підходу.
Річард Ле Месюр’є

@RichardLeMesurier, але метод Commonsware не є правильним, якщо вам потрібні уподобання всередині DrawerLayout
neworld

16

Спираючись на відповідь 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

У серпні 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стиль для макетів, використовуваних для кожного типу переваг, не впливаючи на інші частини вашої діяльності.


1
Я думаю, ви пропускаєте функцію: onCreatePreferences
андроїд розробник

Це врятувало мені день! Цікаво, чому цього не видно в структурі проектів Android Studio ... ?? До речі, у коді є помилка друку. Повинен бути "розширює PreferenceFragmentCompat"
Grzegorz D.

7

Відповідь Tenacious правильна, але ось ще кілька деталей.

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

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

І ви не зможете обійти це, примхливо помістивши свою реалізацію в пакет android.preferences, оскільки непублічні методи в Android API фактично опущені з SDK. Проявивши трохи творчості, що включає рефлексію та динамічні довіреності, ви все ще можете досягти їх. Єдина альтернатива, як каже Tenacious, - роздрібнити весь пакет android.preference, що включає щонайменше 15 класів, 5 макетів і аналогічну кількість елементів style.xml та attrs.xml.

Отже, щоб відповісти на початкове запитання, причина, по якій Google не включила PreferenceFragment в пакет сумісності, полягає в тому, що вони мали б такі самі труднощі, як і Tenacious. Навіть Google не може повернутись у часі та оприлюднити ці методи на старих платформах (хоча, я сподіваюся, що вони будуть робити це у майбутніх випусках).


2

Моя ціль програми - 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();
    }
}

2

Мені потрібно було інтегрувати налаштування в дизайн програми та підтримувати підтримку 2.3 android. Тому мені все ще потрібні «Налаштування».

Після деякого пошуку я знайшов liroid-support-v4-preferencefrag lib. Ця вкладка економить багато часу для копіювання та рефакторингу оригінальних PreferencesFragment, як сказав Tenacious. Добре працює, і користувачі отримують переваги.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.