Що використовувати замість "addPreferencesFromResource" в PreferenceActivity?


360

Щойно я помітив той факт, що метод addPreferencesFromResource(int preferencesResId)позначений застарілим у документації на Android ( Reference Entry ).

На жаль, в описі методу не передбачений альтернативний метод.

Який метод слід використовувати замість цього, щоб підключити preferenceScreen.xml до відповідного PreferenceActivity?


2
Дуже простий підхід забезпечується WannaGetHigh на stackoverflow.com/questions/23523806 / ...
Сабін

Рішення там досі використовується addPreferencesFromResource(int preferencesResId). Я щось пропускаю?
Джаммо

@Jammo Так, але він був переміщений з Активності в Фрагмент, щоб відобразити новий спосіб його виконання -> фрагмент.
WannaGetHigh

Відповіді:


332

В описі методу не передбачений альтернативний метод, оскільки бажаний підхід (на рівні 11 API) полягає у створенні об'єктів PreferenceFragment для завантаження ваших уподобань з файлу ресурсу. Дивіться зразок коду тут: PreferenceActivity


Дуже дякую за вашу відповідь. Я тільки дотримувався застарілих інструкцій з "Video2Brain-Android Development", які привели мене до використання версії методу PreferenceActivity. Btw: Я хотів би оцінити вашу відповідь корисною, якби тільки міг.
mweisz

33
Тепер тільки якщо PreferenceFragment був включений в пакет сумісності було б доцільно використовувати його stackoverflow.com/questions/5501431 / ...
Крістофф

1
Оскільки я використовую панель дій Sherlock, я підписався
Хтось десь

2
Все ж вам потрібно зателефонувати на addPreferencesFromResource (int PreferencesID), якщо ви хочете, щоб програма була сумісною з рівнем api раніше ніж 11 (Android 3.0). Але я думаю, ви могли б також вважати, що ці старі пристрої були зняті.
Ейнар Сундгрен

5
@EinarSundgren Я власник Nexus, і моя максимальна доступна версія - 2,2: ви не зупините мене! Я НІКОЛИ не зникну! Силою Ґрейскулла ... Я маю силу!
TechNyquist

186

Щоб додати більше інформації до правильної відповіді вище, прочитавши приклад від Android-er, я виявив, що ви можете легко перетворити свою активність у вибраний фрагмент. Якщо у вас є така діяльність:

public class MyPreferenceActivity extends PreferenceActivity
{
    @Override
    protected void onCreate(final Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.my_preference_screen);
    }
}

Єдині зміни, які вам доведеться внести, - це створити внутрішній клас фрагмента, перемістити addPreferencesFromResources()фрагмент у фрагмент та викликати фрагмент із дії, наприклад:

public class MyPreferenceActivity extends PreferenceActivity
{
    @Override
    protected void onCreate(final Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        getFragmentManager().beginTransaction().replace(android.R.id.content, new MyPreferenceFragment()).commit();
    }

    public static class MyPreferenceFragment extends PreferenceFragment
    {
        @Override
        public void onCreate(final Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.my_preference_screen);
        }
    }
}

Можуть бути й інші тонкощі щодо складніших уподобань з фрагментів; якщо так, я сподіваюся, що хтось їх тут помітить.


6
Приємно, дякую за це. Ява та такий тип мислення поки що віддалені від мого прекрасного маленького світу. :)
Том

44
Чому вони знеціняться addPreferencesFromResources()в торгівлі за PreferenceFragment? З точки зору початківця це виглядає непотрібним.
Howdy_McGee

4
Для дзвінка потрібен рівень 11 API
мехмет

1
то що робити, якщо API знаходиться на рівні 9? @mehmet
gumuruh

2
Дивовижна відповідь! чи є спосіб досягти цього, не змінюючи змісту android.R.id.content? мені здаються неелегантними чомусь ... (виправте мене, якщо я помиляюся)
tomer.z

37

@Garret Wilson Дуже дякую! Як нооб для кодування Android, я стільки годин зациклювався на проблемі сумісності налаштувань, і я вважаю таким невтішним, що вони зневажили використання деяких методів / підходів для нових, які не підтримуються старими API, таким чином потрібно вдаватися до всіляких обхідних завдань, щоб ваш додаток працював у широкому діапазоні пристроїв. Це справді засмучує!

Ваш клас чудовий, тому що він дозволяє вам продовжувати працювати в нових API-інтерфейсах за такими ж параметрами, як раніше, але він не сумісний із зворотним. Оскільки я намагаюся охопити широкий спектр пристроїв, я трохи попрацював з ним, щоб він працював як на пристроях перед API 11, так і в новіших API:

import android.annotation.TargetApi;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;

public class MyPrefsActivity extends PreferenceActivity
{
    private static int prefs=R.xml.myprefs;

    @Override
    protected void onCreate(final Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        try {
            getClass().getMethod("getFragmentManager");
            AddResourceApi11AndGreater();
        } catch (NoSuchMethodException e) { //Api < 11
            AddResourceApiLessThan11();
        }
    }

    @SuppressWarnings("deprecation")
    protected void AddResourceApiLessThan11()
    {
        addPreferencesFromResource(prefs);
    }

    @TargetApi(11)
    protected void AddResourceApi11AndGreater()
    {
        getFragmentManager().beginTransaction().replace(android.R.id.content,
                new PF()).commit();
    }

    @TargetApi(11)
    public static class PF extends PreferenceFragment
    {       
        @Override
        public void onCreate(final Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(MyPrefsActivity.prefs); //outer class
            // private members seem to be visible for inner class, and
            // making it static made things so much easier
        }
    }
}

Тестується в двох емуляторах (2.2 та 4.2) із успіхом.

Чому мій код виглядає так хитро:

Я прихильник кодування Android, і я не найбільший шанувальник Java.

Щоб уникнути застарілого попередження та змусити Eclipse дозволити мені компілювати, я повинен був вдатися до анотацій, але, здається, вони впливають лише на класи або методи, тому мені довелося перенести код на два нові методи, щоб скористатися цим.

Мені б не хотілося двічі писати свій ідентифікатор ресурсу xml, коли я копіюю та вставляю клас для нового PreferenceActivity, тому я створив нову змінну для зберігання цього значення.

Сподіваюся, це стане в нагоді комусь іншому.

PS: Вибачте за мої переконані погляди, але коли ви з’явитесь нові і знайдете такі перешкоди, ви можете не допомогти, але зірватися!


Ну добре ... Я щойно помітив, що мені доведеться двічі змінити назву зовнішнього класу, коли я його копіюю та вставляю. Насправді є спосіб уникнути цього, передаючи префікси до внутрішнього класу. Ви не можете створювати конструктор внутрішнього класу, що приймає префікси як параметр, оскільки це, очевидно, не рекомендується для похідних класів PreferenceFragment. Крім того, ви не можете створити метод у внутрішньому класі, щоб отримати префікси та викликати addPreferencesFromResource відразу, оскільки addPreferencesFromResource потрібно викликати після виклику super.onCreate, а onCreate не отримує виклик відразу після того, як клас похідного PreferenceFragment має ...
ecv

... було встановлено. Отже, вам потрібно створити нову змінну у внутрішньому класі, створити метод відкритого набору для неї у внутрішньому класі, залишити addPreferencesFromResource там, де він є після виклику super.onCreate, всередині onCreate, інстанціювати внутрішній клас, встановити префікси , і використовуйте його у виклику для отриманняFragmentManager () ..., як і раніше.
ecv

2
Ваш код був рятівником !! Я намагався націлити і на старий, і на новий телефон, і витрачав 3 дні. А відповідь такий простий. Спасибі
Devdatta Tengshe

22

Мій підхід дуже близький до Гаррета Вілсона (спасибі, я проголосував за вас;)

Крім того, це забезпечує сумісність з Android <3.

Я щойно визнав, що моє рішення ще ближче до рішення Кевіна Ремо . Це просто чистіший тріщинець (оскільки він не покладається на тріщину "очікування" антипатерн ).

public class MyPreferenceActivity extends PreferenceActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
            onCreatePreferenceActivity();
        } else {
            onCreatePreferenceFragment();
        }
    }

    /**
     * Wraps legacy {@link #onCreate(Bundle)} code for Android < 3 (i.e. API lvl
     * < 11).
     */
    @SuppressWarnings("deprecation")
    private void onCreatePreferenceActivity() {
        addPreferencesFromResource(R.xml.preferences);
    }

    /**
     * Wraps {@link #onCreate(Bundle)} code for Android >= 3 (i.e. API lvl >=
     * 11).
     */
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private void onCreatePreferenceFragment() {
        getFragmentManager().beginTransaction()
                .replace(android.R.id.content, new MyPreferenceFragment ())
                .commit();
    }
}

Для "реального" (але більш складного) прикладу див. NusicPreferencesActivity та NusicPreferencesFragment .


@SuppressLint("NewApi")- уникайте - будьте точнішими. Ви запустили його на низький апіс? Це кинеVerifyError
Mr_and_Mrs_D

Я тестую вищезазначене на емуляторі, що працює на рівні API 10, APK був створений за допомогою SDK версії 19. Яку версію SDK ви використовували для створення? На якому рівні API пристрою ви працювали? Ви запускали його на емуляторі чи на фізичному пристрої? Коли саме сталася помилка? Якщо будівля Ура з SDK <= 16, дивіться цю відповідь .
шнайтер

Вам не вистачає точки - і додайте @Mr_and_Mrs_D, якщо ви хочете, щоб я був сповіщений. Для VE читайте тут: stackoverflow.com/questions/20271593/… . @SuppressLint("NewApi")Просто поганий стиль
Mr_and_Mrs_D

@M Ну що ж, як щодо пропозиції про те, як уникнути @SuppressLint("NewApi")цієї конкретної ситуації?
schnatterer

@TargetApi(Build.VERSION_CODES.HONEYCOMB)- не всі попередження для будь-яких api :)
Mr_and_Mrs_D

6

Замість винятків просто використовуйте:

if (Build.VERSION.SDK_INT >= 11)

і використовувати

@SuppressLint("NewApi")

для придушення попереджень.


1
бо це не що інше, як аварія: D
Іштяк

1
якщо це аварія ... то спробуйте зловити його: D
gumuruh

0

Замість того, PreferenceActivityщоб безпосередньо використовувати налаштування, використовуйте AppCompatActivityабо еквівалент, який завантажуєPreferenceFragmentCompat те, що завантажує ваші налаштування. Це частина бібліотеки підтримки (зараз Android Jetpack) і забезпечує сумісність назад до API 14.

У ваших build.gradle, додати залежність для бібліотеки підтримки переваги:

dependencies {
    // ...
    implementation "androidx.preference:preference:1.0.0-alpha1"
}

Примітка. Ми припустимо, що у вас уже створені ваші налаштування XML.

Для своєї діяльності створіть новий клас активності. Якщо ви використовуєте матеріальні теми, вам слід розширити AppCompatActivity, але ви можете бути гнучкими в цьому:

public class MyPreferencesActivity extends AppCompatActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_preferences_activity)
        if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.fragment_container, MyPreferencesFragment())
                    .commitNow()
        }
    }
}

Тепер про важливу частину: створіть фрагмент, який завантажує ваші налаштування з XML:

public class MyPreferencesFragment extends PreferenceFragmentCompat {

    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        setPreferencesFromResource(R.xml.my_preferences_fragment); // Your preferences fragment
    }
}

Для отримання додаткової інформації читайте документи для розробників Android для PreferenceFragmentCompat.

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