Что использовать вместо «addPreferencesFromResource» в PreferenceActivity?

360

Я только что заметил тот факт, что этот метод addPreferencesFromResource(int preferencesResId)помечен как устаревший в документации Android ( Справочная запись ).

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

Какой метод следует использовать вместо этого для подключения preferenceScreen.xml к соответствующей PreferenceActivity?

mweisz
источник
2
WannaGetHigh предлагает очень простой подход на stackoverflow.com/questions/23523806/…
Sabin
Решение там все еще использует addPreferencesFromResource(int preferencesResId). Я что-то пропустил ?
Jammo
@Jammo Да, но он был перемещен из Действия в Фрагмент, чтобы отразить новый способ сделать это -> фрагмент.
WannaGetHigh

Ответы:

332

В описании метода нет альтернативного метода, поскольку предпочтительный подход (на уровне API 11) заключается в создании экземпляров объектов PreferenceFragment для загрузки ваших предпочтений из файла ресурсов. Смотрите пример кода здесь: PreferenceActivity

glorifiedHacker
источник
Большое спасибо за ваш ответ. Я просто следовал устаревшим инструкциям "Video2Brain-Android Development", что привело меня к использованию версии метода PreferenceActivity. Кстати, я хотел бы оценить ваш ответ как полезный, если бы только мог.
mweisz
33
Теперь, только если PreferenceFragment был включен в пакет совместимости, имеет смысл использовать его stackoverflow.com/questions/5501431/…
christoff
1
Поскольку я использую Action Bar Sherlock, я следовал за следующим блогом, чтобы решить эту проблему, см. Commonsware.com/blog/2012/10/16/…
Someone Somewhere
2
Тем не менее, вам нужно вызвать addPreferencesFromResource (int PreferencesID), если вы хотите, чтобы приложение было обратно совместимо с уровнем API более раннего, чем 11 (Android 3.0). Но я думаю, вы могли бы также считать эти старые устройства устаревшими.
Эйнар Сундгрен
5
@EinarSundgren Я владелец Nexus One, и моя максимальная доступная версия - 2.2: вы меня не остановите! Я НИКОГДА не буду осужден! Силой Грейскулла ... У меня есть сила!
TechNyquist
186

Чтобы добавить больше информации к правильному ответу выше, после прочтения примера из Android- я обнаружил, что вы можете легко преобразовать ваши действия с предпочтениями в фрагмент предпочтений. Если у вас есть следующие действия:

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
Хорошо, спасибо за это. Ява и этот тип мышления так далеки от моего милого маленького мира .net :)
Том
44
Почему они обесцениваются addPreferencesFromResources()в торговле для PreferenceFragment? Это выглядит ненужным с точки зрения новичка.
Howdy_McGee
4
Для вызова требуется уровень API 11
mehmet
1
так что, если API находится на уровне 9? @mehmet
gumuruh
2
Отличный ответ! Есть ли способ достичь этого без изменения android.R.id.content? мне почему-то кажется не
элегантным
37

@ Гаррет Уилсон Спасибо большое! Как нуб к кодированию 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: Извините за мои убежденные взгляды, но когда вы приходите в себя и обнаруживаете такие недостатки, вы ничего не можете с этим поделать, кроме как расстроиться!

ЭЦВ
источник
О, хорошо ... Я только что заметил, что мне придется менять внешнее имя класса дважды каждый раз, когда я копирую и вставляю его. На самом деле есть способ избежать этого, передавая prefs в innerclass. Вы не можете создавать конструктор внутреннего класса, принимающий префы в качестве параметра, поскольку это явно не рекомендуется для производных классов PreferenceFragment. Кроме того, вы не можете создавать метод во внутреннем классе, чтобы сразу получать prefs и вызывать addPreferencesFromResource, поскольку addPreferencesFromResource необходимо вызывать после вызова super.onCreate, а onCreate не вызывается сразу после того, как производный класс PreferenceFragment имеет ...
ECV
... был создан Поэтому вам нужно создать новую переменную во внутреннем классе, создать для нее открытый метод set во внутреннем классе, оставить addPreferencesFromResource там, где он находится после вызова super.onCreate, внутри onCreate, создать экземпляр внутреннего класса, установить префы и использовать его в вызове getFragmentManager () ... как и раньше.
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 .

schnatterer
источник
@SuppressLint("NewApi")- избегай - будь точнее. Вы использовали его для низкого API? Это броситVerifyError
Mr_and_Mrs_D
Я тестирую вышесказанное на эмуляторе, работающем на уровне API 10, APK был создан с использованием SDK версии 19. Какую версию SDK вы использовали для сборки? На каком уровне API устройства вы его запускали? Вы запускали его на эмуляторе или на физическом устройстве? Когда именно произошла ошибка? Если Ur строит с SDK <= 16, посмотрите этот ответ .
шнаттерер
Вы упускаете суть - и добавьте @Mr_and_Mrs_D, если хотите, чтобы я был уведомлен. Для VE читайте здесь: stackoverflow.com/questions/20271593/… . Это @SuppressLint("NewApi")просто плохой стиль
Mr_and_Mrs_D
@M Ну, а как насчет предложения о том, как избежать @SuppressLint("NewApi")в этой конкретной ситуации?
шнаттерер
@TargetApi(Build.VERSION_CODES.HONEYCOMB)- не все предупреждения для любого API :)
Mr_and_Mrs_D
6

Вместо исключений просто используйте:

if (Build.VERSION.SDK_INT >= 11)

и использовать

@SuppressLint("NewApi")

подавить предупреждения.

Питер
источник
1
потому что он не делает ничего, кроме аварии: D
Ishtiaq
1
если это
потерпит
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.

Вилли Чалмерс III
источник