
示例工程教程【免费下载链接】cw-omnibusSource code to omnibus edition of _The Busy Coders Guide to Android Development_项目地址https://gitcode.com/gh_mirrors/cw/cw-omnibus点击查看免费下载本篇技术指南以 cw-omnibus 仓库The Busy Coders Guide to Android Development配套示例源码集中 Prefs/FragmentsBC/README.markdown 所述示例为核心系统讲解如何借助PreferenceFragment与PreferenceActivity的 header 机制把设置项拆分成多个分组页面。读完本文你将掌握loadHeadersFromResource()加载 header、addPreferencesFromResource()挂载偏好资源、isValidFragment()安全校验以及如何在普通 Fragment 中通过SharedPreferences回读偏好值这一整套实战方案。一、示例要解决的问题一个 Activity 管理多组设置Android 3.0API 11引入PreferenceFragment之后设置界面不再只能由PreferenceActivity单独承载 XML 资源而是可以把每一组设置放进一个 Fragment。FragmentsBC 示例即演示了这种一个设置页 多个偏好分组的组织形态主界面FragmentsDemo是一个普通 Activity仅通过菜单项进入设置页设置页EditPreferences继承PreferenceActivity重写onBuildHeaders()用 header 列表把两组设置串起来两个PreferenceFragment内部类First、Second分别承载两组不同的偏好选项返回主界面后PreferenceContentsFragment从默认SharedPreferences中读取所有设置结果并展示。该示例的配套书籍章节为《using preferences使用偏好设置》在仓库中的完整实现见 Prefs/FragmentsBC 目录。二、整体架构与入口流程2.1 三个 Java 类的分工类文件职责FragmentsDemoFragmentsDemo.java主界面展示当前偏好值菜单触发设置页EditPreferencesEditPreferences.javaPreferenceActivity子类负责 header 路由与 Fragment 白名单PreferenceContentsFragmentPreferenceContentsFragment.java普通 Fragment在onResume()中读取并刷新偏好显示2.2 从主界面到设置页主界面 FragmentsDemo.java 在onCreate()中加载 main.xml后者通过静态fragment标签直接嵌入了PreferenceContentsFragmentfragment xmlns:androidhttp://schemas.android.com/apk/res/android android:layout_widthmatch_parent android:layout_heightmatch_parent android:namecom.commonsware.android.preffragsbc.PreferenceContentsFragment/菜单方面actions.xml 定义了一个settings菜单项图标使用系统自带的android:drawable/ic_menu_preferences并设置showAsActionnever使其始终出现在溢出菜单。点击后经onOptionsItemSelected()启动EditPreferencesOverride public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.settings: startActivity(new Intent(this, EditPreferences.class)); return(true); } return(super.onOptionsItemSelected(item)); }对应地AndroidManifest.xml 中同时注册了主 Activity 与设置 Activity设置页无需LAUNCHER过滤器activity android:name.FragmentsDemo android:labelstring/app_name intent-filter action android:nameandroid.intent.action.MAIN/ category android:nameandroid.intent.category.LAUNCHER/ /intent-filter /activity activity android:name.EditPreferences android:labelstring/app_name/三、核心实现PreferenceActivity Header 路由3.1 onBuildHeaders 与 loadHeadersFromResourceEditPreferences的关键在于重写onBuildHeaders()把 header 资源喂给系统EditPreferences.java#L22-L26public class EditPreferences extends PreferenceActivity { Override public void onBuildHeaders(ListHeader target) { loadHeadersFromResource(R.xml.preference_headers, target); } ... }preference_headers.xml定义了两个分组入口每个header通过android:fragment指向要展示的PreferenceFragment全限定类名preference_headers.xmlpreference-headers xmlns:androidhttp://schemas.android.com/apk/res/android header android:fragmentcom.commonsware.android.preffragsbc.EditPreferences$First android:summarystring/header1summary android:titlestring/header1title /header header android:fragmentcom.commonsware.android.preffragsbc.EditPreferences$Second android:summarystring/header2summary android:titlestring/header2title /header /preference-headers注意类名的写法内部类使用$分隔即EditPreferences$First。title与summary分别来自 strings.xmlheader1titleSome Settings、header1summaryA handful of values for you to tailor、header2titleMore Settings 等。3.2 isValidFragmentAndroid 4.0 的强制安全闸门从 API 19 开始凡是使用 header 加载 Fragment 的PreferenceActivity系统会调用isValidFragment()校验传入的 Fragment 类名防止外部注入恶意 Fragment。示例中通过白名单方式放行自带的两个内部类EditPreferences.java#L29-L36Override protected boolean isValidFragment(String fragmentName) { if (First.class.getName().equals(fragmentName) || Second.class.getName().equals(fragmentName)) { return(true); } return(false); }从源码结构看这是基于 fragment 的偏好页面必不可少的配套代码一旦 header 引用的 Fragment 类名不在此白名单内isValidFragment()返回false系统将拒绝加载该 Fragment。3.3 两个 PreferenceFragment 内部类两个内部类都继承android.preference.PreferenceFragment在onCreate()里通过addPreferencesFromResource()各自加载一份偏好 XMLEditPreferences.java#L38-L54public static class First extends PreferenceFragment { Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences); } } public static class Second extends PreferenceFragment { Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences2); } }First挂载的是 preferences.xmlSecond挂载的是 preferences2.xml。这样一个PreferenceActivity就能承载两个互相独立的设置分组用户通过 header 列表切换。四、偏好资源详解四类常用 Preferencepreferences.xml 聚合了 Android 平台四种最常见的偏好控件是理解PreferenceScreen子节点用法的绝佳范本PreferenceScreen xmlns:androidhttp://schemas.android.com/apk/res/android CheckBoxPreference android:keycheckbox android:summarystring/pref1summary android:titlestring/pref1title/ RingtonePreference android:keyringtone android:showDefaulttrue android:showSilenttrue android:summarystring/pref2summary android:titlestring/pref2title/ EditTextPreference android:dialogTitlestring/dialogtitle android:keytext android:summarystring/pref3summary android:titlestring/pref3title/ ListPreference android:dialogTitlestring/listdialogtitle android:entriesarray/cities android:entryValuesarray/airport_codes android:keylist android:summarystring/pref4summary android:titlestring/pref4title/ /PreferenceScreen各控件要点CheckBoxPreference开关型偏好android:keycheckbox即写入SharedPreferences的键名RingtonePreference铃声选择器android:showDefaulttrue让列表中出现默认铃声项android:showSilenttrue让列表中出现静音项EditTextPreference弹窗文本输入android:dialogTitle指定弹窗标题ListPreference弹窗单选列表android:entries是展示给用户的文本数组android:entryValues是实际写入存储的值数组两者通过数组下标一一对应。第二个分组 preferences2.xml 只包含一个CheckBoxPreferenceandroid:keycheckbox2用于验证多个 Fragment 分组各自独立维护 XML的模式。4.1 配套的数组资源arrays.xml 为ListPreference提供显示名与存储值的成对数据——以宾夕法尼亚州城市为显示名、机场三字码为存储值string-array namecities itemPhiladelphia/item itemPittsburgh/item itemAllentown/Bethlehem/item ... /string-array string-array nameairport_codes itemPHL/item itemPIT/item itemABE/item ... /string-array4.2 文本资源的组织strings.xml 统一维护了 header 标题/摘要、偏好标题/摘要、弹窗标题等文案如pref1titleCheckbox Preference、pref2summaryPick a tone, any tone、listdialogtitleChoose a Pennsylvania city。所有 XML 中均通过string/...引用避免了魔法字符串。五、回读偏好值PreferenceContentsFragment 的 onResume 刷新设置页修改的值保存在应用默认的SharedPreferences中。主界面的 PreferenceContentsFragment.java 在onResume()中统一读取——之所以放在onResume()而不是onCreateView()是为了保证用户从设置页返回时能拿到最新值Override public void onResume() { super.onResume(); SharedPreferences prefs PreferenceManager.getDefaultSharedPreferences(getActivity()); checkbox.setText(Boolean.valueOf(prefs.getBoolean(checkbox, false)).toString()); ringtone.setText(prefs.getString(ringtone, unset)); checkbox2.setText(Boolean.valueOf(prefs.getBoolean(checkbox2, false)).toString()); text.setText(prefs.getString(text, unset)); list.setText(prefs.getString(list, unset)); }要点PreferenceManager.getDefaultSharedPreferences()返回的是与 Preference UI 默认关联的那份偏好文件key 与 XML 中的android:key一一对应每个读取都提供了默认值如false、unset避免首次启动时空指针ringtone键存储的是铃声 URI 字符串checkbox、checkbox2用Boolean.valueOf(...)转为字符串展示。界面侧content.xml 用TableLayoutTableRow布局每行由一个加粗标签 TextView 和一个 30sp 的取值 TextView 组成标签与取值样式定义在 styles.xmllabel样式继承value样式并追加bold与 5dip 右内边距。六、工程配置与运行前提6.1 构建配置app/build.gradlecom.android.application插件compileSdkVersion 21、buildToolsVersion 26.0.2、targetSdkVersion 17根 build.gradleAndroid Gradle 插件版本3.1.4仓库源为google()与jcenter()settings.gradle仅包含:app模块AndroidManifest.xmlminSdkVersion14API 14即 Android 4.0targetSdkVersion14。6.2 主题适配主题在 themes.xml 中基于 Holo 系定义Theme.Holo.Light.DarkActionBar同时在 values-v21/styles.xml 中为 Android 5.0 提供了 Material 变体并指定colorPrimary、colorPrimaryDark、colorAccent三个主题色。运行该示例需要 API 14 以上的设备或模拟器。七、与同目录姊妹示例的横向对照在仓库 Prefs 目录下cw-omnibus 围绕偏好设置提供了多组渐进式示例方便对比不同组织方式示例特点Prefs/Fragment基础版单个PreferenceFragment不使用 headerPrefs/FragmentsBC本文多分组PreferenceActivity header 多个PreferenceFragmentPrefs/NestedScreens进阶在一个PreferenceScreen内嵌套另一个PreferenceScreenPrefs/CustomSubtitle自定义 Fragment 副标题Prefs/DataStore自定义偏好存储后端Prefs/SingleHeader 与 Prefs/SingleHeader2单 header 场景后者额外处理大屏布局对照可见FragmentsBC 的核心价值在于header 驱动的多分组路由它是 NestedScreens单页面内嵌套之外的另一条组织路径——把不同类别的设置拆到不同页面更适合设置项较多、需要按模块划分的应用。八、实战要点小结三层结构PreferenceActivity路由层→ header 资源分组层→PreferenceFragment内容层每层职责单一安全校验不能省API 19 必须重写isValidFragment()并返回白名单判断否则基于 header 的 Fragment 无法加载key 即存储键偏好 XML 中的android:key直接决定SharedPreferences中的键名回读时需保持一致回读时机选 onResume需要实时反映用户修改时把PreferenceManager.getDefaultSharedPreferences()的读取逻辑放在onResume()数组配对ListPreference的entries与entryValues按下标一一对应前者面向用户、后者面向存储。通过本文的源码级拆解你可以直接参考 Prefs/FragmentsBC 的完整实现在自己的应用中快速落地一个设置入口、多组 Fragment 化偏好页面的经典架构。赞分享示例工程教程【免费下载链接】cw-omnibusSource code to omnibus edition of _The Busy Coders Guide to Android Development_项目地址https://gitcode.com/gh_mirrors/cw/cw-omnibus点击查看免费下载相关推荐cw-omnibus 基础组件示例解读用 EditText 构建多行文本输入控件cw omnibus 基础组件示例解读用 EditText 构建多行文本输入控件 导读 本文聚焦 cw omnibus The Busy Coders G示例工程教程cw-omnibus 实战解读基于 SQLiteOpenHelper 的 SQLite 存储示例 ConstantsROWIDcw omnibus 实战解读基于 SQLiteOpenHelper 的 SQLite 存储示例 ConstantsROWID 本篇技术指南以 cw omni示例工程教程循环工程Loop Engineering概念溯源核心来源、思想谱系与仓库落地映射循环工程Loop Engineering概念溯源核心来源、思想谱系与仓库落地映射 导读 本文以仓库中的 Sources Attribution 来源文示例工程教程上一篇手机跑大模型30分钟用koboldcpp在Android上跑通本地AI推理终极实战指南下一篇【亲测免费】 layui-soul-table 项目常见问题解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考