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

304

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

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

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

  • 2
    WannaGetHigh предоставляет очень простой подход на stackoverflow.com/questions/23523806/…
  • 0
    Решение там все еще использует addPreferencesFromResource(int preferencesResId) . Я что-то пропустил ?
Показать ещё 1 комментарий
Теги:

5 ответов

336
Лучший ответ

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

  • 0
    Большое спасибо за ответ. Я просто следовал устаревшим инструкциям «Video2Brain-Android Development», что привело меня к использованию версии метода PreferenceActivity. Кстати, я хотел бы оценить ваш ответ как полезный, если бы я только мог.
  • 33
    Теперь, только если PreferenceFragment был включен в пакет совместимости, имеет смысл использовать его stackoverflow.com/questions/5501431/…
Показать ещё 4 комментария
165

Чтобы добавить дополнительную информацию к правильному ответу выше, после чтения примера из 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
    Хорошо, спасибо за это. Ява и этот тип мышления так далеки от моего милого маленького мира .net :)
  • 43
    Почему они обесценили бы addPreferencesFromResources() в торговле для PreferenceFragment? Это выглядит ненужным с точки зрения новичка.
Показать ещё 6 комментариев
34

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

  • 0
    О, хорошо ... Я только что заметил, что мне придется менять внешнее имя класса дважды каждый раз, когда я копирую и вставляю его. На самом деле есть способ избежать этого, передавая prefs в innerclass. Вы не можете создавать конструктор внутреннего класса, принимающий prefs в качестве параметра, поскольку это явно не рекомендуется для производных классов PreferenceFragment. Кроме того, вы не можете создавать метод во внутреннем классе, чтобы сразу получить prefs и вызывать addPreferencesFromResource, поскольку addPreferencesFromResource необходимо вызывать после вызова super.onCreate, а onCreate не вызывается сразу после того, как производный класс PreferenceFragment имеет ...
  • 0
    ... был создан Поэтому вам нужно создать новую переменную во внутреннем классе, создать для него открытый метод set во внутреннем классе, оставить addPreferencesFromResource там, где он находится после вызова super.onCreate, внутри onCreate, создать экземпляр внутреннего класса, установить префы и использовать его в вызове getFragmentManager () ... как и раньше.
Показать ещё 1 комментарий
22

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

Кроме того, он обеспечивает понижающую совместимость с 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.

  • 0
    @SuppressLint("NewApi") - избегайте - будьте точнее. Вы использовали его для низкого API? Это бросит VerifyError
  • 0
    Я тестирую вышеописанное на эмуляторе, работающем на уровне API 10, APK был создан с использованием SDK версии 19. Какую версию SDK вы использовали для сборки? На каком уровне API устройства вы его запускали? Вы запускали его на эмуляторе или на физическом устройстве? Когда именно произошла ошибка? Если Ur строит с SDK <= 16, посмотрите этот ответ .
Показать ещё 4 комментария
5

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

if (Build.VERSION.SDK_INT >= 11)

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

@SuppressLint("NewApi")

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

  • 13
    подавлять предупреждения не очень хорошая идея :)
  • 0
    @ Лукап, почему это не очень хорошая идея?
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню