PreferenceFragment 是否故意被排除在兼容性包之外?

我希望写的首选项可以应用到3.0和3.0之前的设备。发现 PreferenceActivity包含不推荐的方法(尽管在附带的示例代码中使用了这些方法) ,我查看了 PreferenceFragement和兼容性包来解决我的问题。

但是,似乎 PreferenceFragment不在兼容性包中。有人能告诉我这是不是故意的吗?如果是这样,我是否可以很容易地瞄准一系列设备(例如 < 3.0和 > = 3.0) ,或者我必须跳过这些障碍?如果不是有意排除它,我们能期待兼容性包的新版本吗?或者还有其他可以安全使用的变通方法?

干杯

詹姆斯

38650 次浏览

发现 PreferenceActivity 包含不推荐的方法(尽管在附带的示例代码中使用了这些方法)

不推荐使用的方法在 Android 3.0中已经被废弃了。它们在所有版本的 Android 上都非常好,但是方向是在 Android 3.0或更高版本上使用 PreferenceFragment

有人能告诉我这是不是故意的吗?

我猜这是工程时间的问题,但这只是猜测。

如果是这样,我是否可以很容易地瞄准一系列设备(例如 < 3.0和 > = 3.0) ,或者我必须跳过这些障碍?

我认为这是“容易的”。有两个独立的 PreferenceActivity实现,一个使用首选项头和 PreferenceFragments,另一个使用原始方法。在需要的地方选择正确的选项(例如,当用户单击选项菜单项时)。下面是一个示例项目演示了这一点。或者,使用单个 PreferenceActivity来处理这两种情况,如 这个样本项目

如果不是有意排除它,我们能期待兼容性包的新版本吗?

等我们其他人发现的时候你就知道了,也就是说,如果它发射的话。

或者还有其他可以安全使用的变通方法?

看上面。

来自@CommonsWare 的答案的微妙含义是——您的应用程序必须在兼容性 API 和内置片段 API 之间做出选择(因为 SDK 11左右)。事实上,“轻松”建议就是这样做的。换句话说,如果你想使用 PreferenceFragment,你的应用程序需要使用内置的片段 API,并处理 PreferenceActivity 上不推荐的方法。相反,如果你的应用程序使用 compat 很重要。你将面临根本没有 PreferenceFragment 类的情况。因此,目标设备不是一个问题,但是当您必须选择一个或另一个 API 并因此将您的设计提交给不可预见的变通方法时,就会发生跳环。我需要电脑。因此我将创建我自己的 PreferenceFragment 类,看看它是如何工作的。在最坏的情况下,我只需要创建一个普通的(片段)布局,然后手动将视图组件绑定到 sharedprefs..。

编辑: 在尝试并查看了 http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/preference/PreferenceFragment.java?av=h的代码之后——创建我自己的 PreferenceFragment 是不可能的。似乎在 PreferenceManager 中自由使用 package-private 而不是‘ protected’是主要的阻碍因素。它看起来真的没有任何安全性或者真正好的动机去做这些事情,它对于单元测试来说也不是很好,但是好吧... ... 我想输入更少了... ..。

编辑 v2: 事实上它确实发生了,而且起作用了。使代码能够与兼容性 API JAR 一起工作绝对是一个令人头疼的问题。我必须将大约70% 的 com.Android.ferences 包从 SDK 复制到我的应用程序中,然后再与 Android 中通常质量平庸的 Java 代码较量。我用的是 SDK 的 v14。对于一个谷歌的工程师来说,做我所做的事情要容易得多,这与我听到的一些主要的安卓工程师关于这个话题的说法相反。

顺便说一下,我有没有说“瞄准设备不是问题”?它完全是... 如果您使用 com.android.ferences,那么在不进行重大重构的情况下,您将无法与 CompatibilityAPI 进行交换。好玩的木头!

基于 CommonsWare 的回答以及 Tenicious 的观察,我提出了一个单一的后代类解决方案,能够以最小的麻烦和没有代码或资源重复的方式针对所有当前的 Android API 版本。请看我对相关问题的回答: 偏好活动 Android 4.0及更早版本

或者在我的博客上: Http://www.blackmoonit.com/2012/07/all_api_prefsactivity/

在运行4.0.3和4.0.4的两款平板电脑上测试,在运行4.0.4和2.3.3的手机上测试,在运行1.6的模拟器上测试。

顽强的回答是正确的,但这里有一些更多的细节。

之所以不能“手动创建一个普通的布局并将视图组件绑定到 sharedprefs”,是因为 android.ferences API 中存在一些令人惊讶的遗漏。PreferenceActivity 和 PreferenceFragment 都可以访问关键的非公共 PreferenceManager 方法,没有这些方法,您就无法实现自己的首选项 UI。

特别是,要从 XML 文件构造 Preferences 层次结构,您需要使用 PreferenceManager,但是 PreferenceManager 的所有构造函数要么是包私有的,要么是隐藏的。将 Preferences onClick 侦听器附加到活动的方法也是 package-private。

你不能通过偷偷地把你的实现放在 Android.ferences 包中来解决这个问题,因为 Android API 中的非公共方法实际上在 SDK 中被忽略了。通过一点创造性,包括反思和动态代理,您仍然可以获得它们。正如 Tenicious 所说,唯一的替代方法是分支整个 android.ferences 包,包括至少15个类、5个布局以及类似数量的 style.xml 和 attrs.xml 元素。

所以,为了回答最初的问题,Google 之所以没有在兼容包中包含 PreferenceFragment,是因为他们遇到的困难和 Tenicious 和我遇到的完全一样。即使是 Google 也不能回到过去,让这些方法在旧的平台上公开(尽管我希望他们在未来的版本中这样做)。

我的应用程序目标是 API + 14,但是由于使用支持库进行一些奇特的导航,我不能使用 android.app.Fragment,只能使用 android.support.v4.app.Fragment,但是我还需要使用 PreferenceFragment,而不需要对后面的代码进行大的更改。

因此,我的简单解决方案是同时拥有支持库和 PreferenceFragment:

private android.support.v4.app.Fragment fragment;
private android.app.Fragment nativeFragment = null;


private void selectItem(int position) {
fragment = null;
boolean useNativeFragment = false;
switch (position) {
case 0:
fragment = new SampleSupprtFragment1();
break;
case 1:
fragment = new SampleSupprtFragment2();
break;
case 2:
nativeFragment = new SettingsFragment();
useNativeFragment = true;
break;
}
if (useNativeFragment) {
android.app.FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.content_frame, nativeFragment).commit();
} else {
if (nativeFragment != null) {
getFragmentManager().beginTransaction().remove(nativeFragment)
.commit();
nativeFragment = null;
}
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.content_frame, fragment).commit();
}
}

我需要将首选项集成到应用程序的设计中,并保持对2.3 android 的支持,所以我仍然需要首选项片段。

经过一番搜索,我找到了 Android-support-v4-偏好片段 lib。这个 lib 节省了复制和重构原始 Preferences 片段的大量时间。工作良好,用户喜欢。

看到 首选项片段-Compat从 Machinarius。这是很容易下降与梯度,我忘记了它甚至有。

compile 'com.github.machinarius:preferencefragment:0.1.1'

重要更新: v7 support library最新修订本现在有一个原生的 偏好片段

2015年8月,谷歌发布了新的 首选项支持库 v7

现在您可以将 偏好片段与任何 ActivityAppCompatActivity一起使用

public static class PrefsFragment extends PreferenceFragmentCompat {


@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);


// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preferences);
}
}

你必须在你的主题中设置 preferenceTheme:

<style name="AppTheme" parent="@style/Theme.AppCompat.Light">
...
<item name="preferenceTheme">@style/PreferenceThemeOverlay</item>
</style>

通过这种方式,您可以自定义 preferenceTheme来设计每个首选项类型所使用的布局,而不会影响活动的其他部分。