尝试在Android 4.0中的ApiDemos中使用不同偏好设置活动时,我发现PreferencesFromCode.java中的某些方法已被弃用。
所以我的问题是:如果我使用PreferenceFragment,它会适用于所有版本还是只适用于3.0或4.0及更高版本?
如果是这样,我应该使用什么才能在2.2和2.3上运行?
尝试在Android 4.0中的ApiDemos中使用不同偏好设置活动时,我发现PreferencesFromCode.java中的某些方法已被弃用。
所以我的问题是:如果我使用PreferenceFragment,它会适用于所有版本还是只适用于3.0或4.0及更高版本?
如果是这样,我应该使用什么才能在2.2和2.3上运行?
PreferenceFragment
不支持 Android 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
的实现,分别用于支持或不支持PreferenceFragments
的API级别:
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文件,对于API级别< 11,您需要手动加载每个XML文件,并且两个活动都使用相同的首选项。
@Mef,你的答案还可以更简单,这样你就不需要使用PreferencesActivity和OtherPreferencesActivity(拥有2个PrefsActivities非常麻烦)。
我发现你可以将onBuildHeaders()方法放入你的PreferencesActivity中,在Android v11之前的版本中不会抛出错误。将loadHeadersFromResource()方法放在onBuildHeaders中,在2.3.6上没有抛出异常,但在Android 1.6上会。经过一些尝试,我发现以下代码可以在所有版本中工作,只需要一个Activity(大大简化了问题)。
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) {
}
}
}
这样你只需要一个活动(activity),一个在AndroidManifest.xml中的入口,以及在调用偏好设置时只需要一行代码:
startActivity(new Intent(this, PreferencesActivity.class);
更新于2013年10月: Eclipse / Lint会警告您使用已弃用的方法,但只需忽略警告即可。我们仅在必须使用它时使用该方法,即每当我们没有v11+风格偏好并且必须使用它时,这是可以的。当您已经考虑了它时,请不要因为过时的代码而感到恐慌,Android不会很快删除已弃用的方法。如果真的发生了这种情况,您甚至不再需要这个类,因为您将被迫仅针对较新的设备进行目标设置。弃用机制存在的目的是警告您有更好的方法来处理最新API版本上的某些内容,但一旦您已考虑到这一点,您可以从那时起安全地忽略警告。从代码中删除所有对已弃用方法的调用将仅导致您的代码仅在较新的设备上运行-从而完全抵消了向后兼容性。
PreferenceFragment
类的地方。 - Luis A. FloritPreferenceActivity
的方法,而不是PreferenceFragment
的方法。例如,在你的代码中,findPreference()
是从PreferenceActivity
中获取的,这就是为什么你会得到相同的过时警告。换句话说,我真的不明白你的代码如何与PreferenceFragment
一起工作。事实上,你从未继承这个类。 - Luis A. Florit之前的问题在于它会在早期版本的设备上将所有首选项堆叠到单个屏幕上(由于多次调用addPreferenceFromResource()
)。
如果您需要首先显示列表屏幕,然后再显示首选项屏幕(例如使用首选项标题),则应使用兼容首选项的官方指南。
所以,从preference_header_legacy.xml这个文件开始,适用于HoneyComb之前的Android系统。
<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-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>
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"
/>
mavenCentral
上有一个AAR
文件,所以如果你正在使用Gradle
,你可以轻松地将其包含进来。
compile 'com.github.machinarius:preferencefragment:0.1.1'