PreferenceActivity Android 4.0 и более ранних версий
Попробовав различные действия в ApiDemos для Android 4.0, я вижу в коде, что некоторые методы устарели в PreferencesFromCode.java, например.
Итак, мой вопрос: если я использую PreferenceFragment, будет ли он работать для всех версий или только 3.0 или 4.0 и выше?
Если да, то что я должен использовать, это работает и для 2.2 и 2.3?
Ответы
Ответ 1
PreferenceFragment
не будет работать с 2.2 и 2.3 (только для уровня API 11 и выше). Если вы хотите предложить лучший пользовательский интерфейс и по-прежнему поддерживать старые версии Android, лучшей практикой здесь является реализация двух классов PreferenceActivity
и решение во время выполнения, которое нужно вызвать. Однако этот метод по-прежнему включает вызывать устаревшие API, но вы не можете этого избежать.
Так, например, у вас есть preference_headers.xml
:
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android" >
<header android:fragment="your.package.PrefsFragment"
android:title="...">
<extra android:name="resource" android:value="preferences" />
</header>
</preference-headers>
и стандартный preferences.xml
(который не сильно изменился с более низких уровней API):
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" android:title="...">
...
</PreferenceScreen>
Затем вам понадобится реализация PreferenceFragment
:
public static class PrefsFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
}
И, наконец, вам нужны две реализации PreferenceActivity
, для уровней API, поддерживающих или не поддерживающих PreferenceFragments
:
public class PreferencesActivity extends PreferenceActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
addPreferencesFromResource(R.xml.other);
}
}
и
public class OtherPreferencesActivity extends PreferenceActivity {
@Override
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.preference_headers, target);
}
}
В тот момент, когда вы хотите отобразить экран предпочтений для пользователя, вы решаете, с чего начать:
if (Build.VERSION.SDK_INT < 11) {
startActivity(new Intent(this, PreferencesActivity.class));
} else {
startActivity(new Intent(this, OtherPreferencesActivity.class));
}
Итак, в основном, у вас есть xml файл на фрагмент, вы загружаете каждый из этих xml файлов вручную для уровней API < 11, и обе действия используют те же настройки.
Ответ 2
@Mef. Ваш ответ может быть упрощен еще больше, так что вам не нужны оба PreferencesActivity и OtherPreferencesActivity (с 2 PrefsActivities - PITA).
Я обнаружил, что вы можете поместить метод onBuildHeaders() в свою PreferencesActivity, и никакие ошибки не будут выпущены версиями Android до версии v11. Наличие loadHeadersFromResource() внутри onBuildHeaders не выбрасывал и исключение на 2.3.6, а делал на Android 1.6. Однако после некоторого вмешательства я обнаружил, что следующий код будет работать во всех версиях, так что требуется только одно действие (что значительно упрощает).
public class PreferencesActivity extends PreferenceActivity {
protected Method mLoadHeaders = null;
protected Method mHasHeaders = null;
/**
* Checks to see if using new v11+ way of handling PrefFragments.
* @return Returns false pre-v11, else checks to see if using headers.
*/
public boolean isNewV11Prefs() {
if (mHasHeaders!=null && mLoadHeaders!=null) {
try {
return (Boolean)mHasHeaders.invoke(this);
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
}
return false;
}
@Override
public void onCreate(Bundle aSavedState) {
//onBuildHeaders() will be called during super.onCreate()
try {
mLoadHeaders = getClass().getMethod("loadHeadersFromResource", int.class, List.class );
mHasHeaders = getClass().getMethod("hasHeaders");
} catch (NoSuchMethodException e) {
}
super.onCreate(aSavedState);
if (!isNewV11Prefs()) {
addPreferencesFromResource(R.xml.preferences);
addPreferencesFromResource(R.xml.other);
}
}
@Override
public void onBuildHeaders(List<Header> aTarget) {
try {
mLoadHeaders.invoke(this,new Object[]{R.xml.pref_headers,aTarget});
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
}
}
Таким образом вам нужно только одно действие, одна запись в вашем AndroidManifest.xml и одна строка при вызове ваших настроек:
startActivity(new Intent(this, PreferencesActivity.class);
ОБНОВЛЕНИЕ октябрь 2013:
Eclipse/Lint предупредит вас об использовании устаревшего метода, но просто игнорирует предупреждение. Мы используем этот метод только тогда, когда мы должны это делать, когда у нас нет предпочтений стиля v11 + и он должен его использовать, и это нормально. Не бойтесь устаревшего кода, когда вы его учли, Android не будет удалять устаревшие методы в ближайшее время. Если это когда-либо происходило, вам больше не понадобится этот класс, так как вы будете вынуждены использовать только новые устройства. Устаревший механизм заключается в том, чтобы предупредить вас, что есть лучший способ обработать что-то в последней версии API, но после того, как вы учли его, вы можете смело игнорировать это предупреждение. Удаление всех вызовов на устаревшие методы приведет только к тому, что ваш код будет работать только на более новых устройствах, тем самым отрицая необходимость обратной совместимости вообще.
Ответ 3
Там новый lib, который может помочь.
UnifiedPreference - это библиотека для работы со всеми версиями Android Preference от API v4 и выше.
Ответ 4
Проблема с предыдущими ответами заключается в том, что он будет складывать все настройки на один экран на устройствах pre-Honecomb (из-за нескольких вызовов addPreferenceFromResource()
).
Если вам нужен первый экран в виде списка, а затем экран с настройками (например, с использованием заголовков предпочтений), вы должны использовать Официальное руководство по совместимым настройкам
Ответ 5
Я хотел бы указать, что если вы начнете с http://developer.android.com/guide/topics/ui/settings.html#PreferenceHeaders и проделаете свой путь до раздела "Поддержка старых версий с предпочтением заголовки", это будет иметь больше смысла. Руководство там очень полезно и хорошо работает. Вот явный пример, следующий за их руководством:
Итак, начните с файла preference_header_legacy.xml для систем Android до HoneyComb
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<Preference
android:title="OLD Test Title"
android:summary="OLD Test Summary" >
<intent
android:targetPackage="example.package"
android:targetClass="example.package.SettingsActivity"
android:action="example.package.PREFS_ONE" />
</Preference>
Далее создайте файл preference_header.xml для систем Android с помощью HoneyComb +
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
<header
android:fragment="example.package.SettingsFragmentOne"
android:title="NEW Test Title"
android:summary="NEW Test Summary" />
</preference-headers>
Далее создайте файл preferences.xml, чтобы сохранить ваши настройки...
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<CheckBoxPreference
android:key="pref_key_auto_delete"
android:summary="@string/pref_summary_auto_delete"
android:title="@string/pref_title_auto_delete"
android:defaultValue="false" />
</PreferenceScreen>
Далее создайте файл SettingsActivity.java
package example.project;
import java.util.List;
import android.annotation.SuppressLint;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceActivity;
public class SettingsActivity extends PreferenceActivity{
final static String ACTION_PREFS_ONE = "example.package.PREFS_ONE";
@SuppressWarnings("deprecation")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String action = getIntent().getAction();
if (action != null && action.equals(ACTION_PREFS_ONE)) {
addPreferencesFromResource(R.xml.preferences);
}
else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
// Load the legacy preferences headers
addPreferencesFromResource(R.xml.preference_header_legacy);
}
}
@SuppressLint("NewApi")
@Override
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.preference_header, target);
}
}
Далее создайте класс SettingsFragmentOne.java
package example.project;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.preference.PreferenceFragment;
@SuppressLint("NewApi")
public class SettingsFragmentOne extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
}
AndroidManifest.xml, добавил этот блок между тегами <application>
<activity
android:label="@string/app_name"
android:name="example.package.SettingsActivity"
android:exported="true">
</activity>
и, наконец, для тега <wallpaper>
...
<wallpaper xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/description"
android:thumbnail="@drawable/ic_thumbnail"
android:settingsActivity="example.package.SettingsActivity"
/>
Ответ 6
Я использую эту библиотеку, которая имеет AAR
в mavenCentral
, поэтому вы можете легко включить ее, если используете Gradle
.
compile 'com.github.machinarius:preferencefragment:0.1.1'