PreferenceActivity Android 4.0及更早版本
例如,在ApiDemos for Android 4.0中尝试不同的首选项活动,我在代码中看到有些方法在PreferencesFromCode.java中不推荐使用。
所以我的问题是:如果我使用PreferenceFragment,它会适用于所有版本或只有3.0或4.0和以上?
如果是这样的话,我应该怎样使用它,以及2.2和2.3的工作呢?
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文件,您手动为API级别<11加载这些xml文件,并且这两个Activities都使用相同的首选项。
@Mef你的答案可以更简化,所以你不需要同时使用PreferencesActivity和OtherPreferencesActivity(有2个PrefsActivities是一个PITA)。
我发现你可以把onBuildHeaders()方法放到你的PreferencesActivity中,并且在v11以前的Android版本中不会出现任何错误。 在onBuildHeaders中有loadHeadersFromResource()在2.3.6上没有抛出和exception,但是在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年10月:Eclipse / Lint将警告您使用弃用的方法,但只是忽略警告。 我们只在需要的时候才使用这个方法,也就是每当我们没有v11 +样式偏好的时候,必须使用它,这是可以的。 不要害怕Deprecated代码,当你已经说明了,Android不会很快删除废弃的方法。 如果它真的发生了,你甚至不需要这个类,因为你将被迫仅仅瞄准新的设备。 弃用的机制是在那里警告你有一个更好的方法来处理最新的API版本的东西,但一旦你已经说明了,你可以放心地忽略这个警告。 删除所有对不推荐使用的方法的调用只会导致您的代码只能在较新的设备上运行,从而无需向后兼容。
有一个新的lib可能会有所帮助。
UnifiedPreference是一个库,用于处理来自API v4及更高版本的Android Preference包的所有版本。
先前答案的问题是,它会将所有首选项叠加到预Honecomb设备上的单个屏幕(由于多次调用addPreferenceFromResource()
)。
如果您需要第一个屏幕作为列表,然后是首选屏幕(如使用首选项标题),则应使用官方指南以兼容首选项
我想指出的是,如果你从http://developer.android.com/guide/topics/ui/settings.html#PreferenceHeaders开始,继续阅读“支持具有偏好标题的旧版本”部分,更有意义。; 这个指南非常有帮助,并且工作得很好。 下面是他们的指南中的一个明确的例子:
因此,在HoneyComb之前,先从android系统的文件preference_header_legacy.xml开始
<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>
接下来使用HoneyComb +为android系统创build文件preference_header.xml
<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>
接下来创build一个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>
接下来创buildSettingsActivity.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); } }
接下来创build类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'