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

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

К сожалению, альтернативный метод не указан в описании метода.

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

Ответ 1

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

Ответ 2

Чтобы добавить дополнительную информацию к правильному ответу выше, после чтения примера из 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);
        }
    }
}

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

Ответ 3

@Garret Wilson Большое вам спасибо! Как noob для кодирования 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).

Почему мой код выглядит так дерьмово:

Я noob для кодирования Android, и я не самый большой поклонник java.

Чтобы избежать устаревшего предупреждения и заставить Eclipse разрешить мне скомпилировать, мне приходилось прибегать к аннотациям, но они, похоже, влияют только на классы или методы, поэтому мне пришлось переместить код на два новых метода, чтобы воспользоваться преимуществами из этого.

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

Я надеюсь, что это будет полезно кому-то другому.

P.S.: Извините за мои упрямые взгляды, но когда вы приходите новыми и находите такие недостатки, вы не можете помочь, но расстраиваться!

Ответ 4

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

Кроме того, он обеспечивает понижающую совместимость с Android < 3.

Я только узнал, что мое решение еще ближе к тому, что было сделано Кевином Ремо. Это просто немного чище (поскольку он не полагается на "expection" antipattern).

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.

Ответ 5

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

if (Build.VERSION.SDK_INT >= 11)

и используйте

@SuppressLint("NewApi")

для подавления предупреждений.