blob: 72558c76c1df51c13f4ebd3f6d8bf51bf0580e9e [file] [log] [blame]
Android Partner Docs362780b2018-01-08 12:53:50 -08001<html devsite><head>
Android Partner Docsc331c4c2018-11-09 09:43:40 -08002 <title>信息架构</title>
Android Partner Docs362780b2018-01-08 12:53:50 -08003 <meta name="project_path" value="/_project.yaml"/>
4 <meta name="book_path" value="/_book.yaml"/>
5 </head>
6 <body>
Android Partner Docsc331c4c2018-11-09 09:43:40 -08007
Android Partner Docs362780b2018-01-08 12:53:50 -08008 <!--
9 Copyright 2017 The Android Open Source Project
10
11 Licensed under the Apache License, Version 2.0 (the "License");
12 you may not use this file except in compliance with the License.
13 You may obtain a copy of the License at
14
15 http://www.apache.org/licenses/LICENSE-2.0
16
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
22 -->
23
24<p>
Android Partner Docsc331c4c2018-11-09 09:43:40 -080025Android 8.0 为“设置”应用引入了全新的信息架构,以便简化设置组织方式,让用户更轻松地快速找到自定义 Android 设备所需的设置。
26
27Android 9 引入了一些改进,以提供更多设置功能并简化实现。
Android Partner Docs362780b2018-01-08 12:53:50 -080028</p>
29
30<h2 id="examples-and-source">示例和源代码</h2>
31
32<p>
33“设置”中的大多数页面目前都是使用新框架实现的。一个很好的例子是 DisplaySettings:<code>packages/apps/Settings/src/com/android/settings/DisplaySettings.java</code>
34</p>
35
36<p>
Android Partner Docsc331c4c2018-11-09 09:43:40 -080037下面列出了重要组件的文件路径:
Android Partner Docs362780b2018-01-08 12:53:50 -080038</p>
39
Android Partner Docsc331c4c2018-11-09 09:43:40 -080040<ul>
41<li><strong>CategoryKey</strong><code>packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java</code></li>
42<li><strong>DashboardFragmentRegistry</strong><code>packages/apps/Settings/src/com/android/settings/dashboard/DashboardFragmentRegistry.java</code></li>
43<li><strong>DashboardFragment</strong><code>packages/apps/Settings/src/com/android/settings/dashboard/DashboardFragment.java</code></li>
44<li><strong>AbstractPreferenceController</strong><code>frameworks/base/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
45</code></li>
46<li><strong>BasePreferenceController</strong>(已在 Android 9 中引入):<code>packages/apps/Settings/src/com/android/settings/core/BasePreferenceController.java</code></li>
47</ul>
Android Partner Docs362780b2018-01-08 12:53:50 -080048
49<h2 id="implementation">实现</h2>
50
51<p>
Android Partner Docsc331c4c2018-11-09 09:43:40 -080052建议设备制造商调整现有的“设置”信息架构,并根据需要插入其他设置页面以容纳合作伙伴专用功能。将偏好设置从旧版页面(作为 <code>SettingsPreferencePage</code> 实现的页面)移到新页面(使用 <code>DashboardFragment</code> 实现的页面)可能很复杂。旧版页面中的偏好设置在实现时很可能没有创建 <code>PreferenceController</code>
Android Partner Docs362780b2018-01-08 12:53:50 -080053</p>
54
55<p>
Android Partner Docsc331c4c2018-11-09 09:43:40 -080056因此,将偏好设置从旧版页面移到新页面时,您需要先创建一个 <code>PreferenceController</code>,并将代码移到该控制器中,然后才能在新的 <code>DashboardFragment</code> 中对其进行实例化。<code>PreferenceController</code> 所需的 API 会在其名称中加以说明并记录在 Javadoc 中。
Android Partner Docs362780b2018-01-08 12:53:50 -080057</p>
58
59<p>
Android Partner Docsc331c4c2018-11-09 09:43:40 -080060强烈建议为每个 <code>PreferenceController</code> 添加单元测试。如果更改要提交到 AOSP,则需要有单元测试。要详细了解如何编写基于 Robolectric 的测试,请参阅 readme 文件 <code>packages/apps/Settings/tests/robotests/README.md</code>
Android Partner Docs362780b2018-01-08 12:53:50 -080061</p>
62
Android Partner Docsc331c4c2018-11-09 09:43:40 -080063<h3 id="plugin">插件式信息架构</h3>
Android Partner Docs362780b2018-01-08 12:53:50 -080064
65<p>
66每个设置项都作为偏好设置进行实现。可以轻松地将偏好设置从一个页面移到另一个页面。
67</p>
68
69<p>
Android Partner Docsc331c4c2018-11-09 09:43:40 -080070为了更轻松地移动多个设置,Android 8.0 引入了包含设置项的插件式托管方片段。设置项被建模为插件式控制器。因此,设置页面由单个托管方片段和多个设置控制器构成。
Android Partner Docs362780b2018-01-08 12:53:50 -080071</p>
72
73<h3 id="dashboard-fragment">DashboardFragment</h3>
74
75<p>
Android Partner Docs964c5952019-01-25 14:26:34 -080076<code>DashboardFragment</code> 是插件式偏好设置控制器的托管方。该片段继承自 <code>PreferenceFragment</code>,并具有用于扩展和更新静态偏好设置列表与动态偏好设置列表的钩子。
Android Partner Docs362780b2018-01-08 12:53:50 -080077</p>
78
79<h3 id="static-preferences">静态偏好设置</h3>
80
81<p>
Android Partner Docsc331c4c2018-11-09 09:43:40 -080082静态偏好设置列表在 XML 中使用 <code>&lt;Preference&gt;</code> 标记定义。<code>DashboardFragment</code> 实现使用 <code>getPreferenceScreenResId()</code> 方法定义哪个 XML 文件包含要显示的静态偏好设置列表。
83</p>
Android Partner Docs362780b2018-01-08 12:53:50 -080084
85<h3 id="dynamic-preferences">动态偏好设置</h3>
86
87<p>
Android Partner Docsc331c4c2018-11-09 09:43:40 -080088动态项表示具有 intent 的图块,会引向外部或内部 Activity。通常,intent 会引向不同的设置页面。例如,“设置”首页中的“Google”设置项就是一个动态项。动态项在 <code>AndroidManifest</code> 中定义(请参见下文),并通过 <code>FeatureProvider</code>(定义为 <code>
89DashboardFeatureProvider</code>)加载。
Android Partner Docs362780b2018-01-08 12:53:50 -080090</p>
91
92<p>
Android Partner Docsc331c4c2018-11-09 09:43:40 -080093与静态配置的设置相比,动态设置更耗费资源,因此开发者通常应将设置实现为静态设置。不过在以下任一情况下,动态设置可能非常有用:
Android Partner Docs362780b2018-01-08 12:53:50 -080094</p>
95
96<ul>
97<li>设置未在“设置”应用中直接实现(例如,注入由 OEM/运营商应用实现的设置)。</li>
98<li>设置应显示在“设置”首页上。</li>
Android Partner Docsc331c4c2018-11-09 09:43:40 -080099<li>您已有相应设置的 Activity,不想实现额外的静态配置。</li>
Android Partner Docs362780b2018-01-08 12:53:50 -0800100</ul>
101
102<p>
Android Partner Docsc331c4c2018-11-09 09:43:40 -0800103要将 Activity 配置为动态设置,请执行以下操作:
Android Partner Docs362780b2018-01-08 12:53:50 -0800104</p>
105
106<ul>
Android Partner Docsc331c4c2018-11-09 09:43:40 -0800107<li>向 Activity 添加 Intent 过滤器,将其标记为动态设置。</li>
108<li>将其所属的类别告诉“设置”应用。类别是一个常量,在 <code>CategoryKey</code> 中定义。</li>
109<li>选做:系统显示设置时,添加摘要文字。</li>
Android Partner Docs362780b2018-01-08 12:53:50 -0800110</ul>
111
112<p>
Android Partner Docsc331c4c2018-11-09 09:43:40 -0800113以下是从“设置”应用中提取的 <code>DisplaySettings</code> 示例。
Android Partner Docs362780b2018-01-08 12:53:50 -0800114</p>
115
116<pre class="prettyprint">
117&lt;activity android:name="Settings$DisplaySettingsActivity"
118 android:label="@string/display_settings"
119 android:icon="@drawable/ic_settings_display"&gt;
120 &lt;!-- Mark the activity as a dynamic setting --&gt;
121 &lt;intent-filter&gt;
122 &lt;action android:name="com.android.settings.action.IA_SETTINGS" /&gt;
123 &lt;/intent-filter&gt;
124 &lt;!-- Tell Settings app which category it belongs to --&gt;
125 &lt;meta-data android:name="com.android.settings.category"
126 android:value="com.android.settings.category.ia.homepage" /&gt;
127 &lt;!-- Add a summary text when the setting is displayed --&gt;
128 &lt;meta-data android:name="com.android.settings.summary"
129 android:resource="@string/display_dashboard_summary"/&gt;
130 &lt;/activity&gt;
131</pre>
132
133<p>
Android Partner Docsc331c4c2018-11-09 09:43:40 -0800134在呈现时,片段会请求提供在 <code>AndroidManifest</code> 中定义的静态 XML 和动态设置中的偏好设置列表。无论 <code>PreferenceController</code> 是在 Java 代码中还是在 XML 中定义的,<code>DashboardFragment</code> 都通过 <code>PreferenceController</code> 管理每个设置的处理逻辑(请参见下文)。然后,它们将以混合列表的形式显示在界面中。
Android Partner Docs362780b2018-01-08 12:53:50 -0800135</p>
136
137<h3 id="preference-controller">PreferenceController</h3>
138
Android Partner Docsc331c4c2018-11-09 09:43:40 -0800139<p>如本部分所述,在 Android 9 中和在 Android 8.x 中实现 <code>PreferenceController</code> 有一些不同。</p>
140
141<h4>Android 9 版本中的 PreferenceController</h4>
142
143<p><code>PreferenceController</code> 包含与偏好设置进行交互所需的所有逻辑,包括显示、更新、编入搜索索引等。</p>
144
145<p><code>PreferenceController</code> 的接口被定义为 <code>BasePreferenceController</code>。例如,请参阅 <code>packages/apps/Settings/src/com/android/settings/core/
146BasePreferenceController.java</code> 中的代码</p>
147
148<p><code>BasePreferenceController</code> 有多个子类,每个子类都分别映射到“设置”应用默认支持的一个特定界面样式。例如,<code>TogglePreferenceController</code> 包含的某个 API 直接映射到用户应如何与基于切换开关的偏好设置界面进行交互。</p>
149
150<p><code>BasePreferenceController</code> 具有 <code>getAvailabilityStatus()</code><code>displayPreference()</code><code>handlePreferenceTreeClicked(),</code> 等 API。有关每个 API 的详细文档位于相应的接口类中。</p>
151
152<p>实现 <code>BasePreferenceController</code>(及其子类,例如 <code>TogglePreferenceController</code>)时的一个限制是,构造函数签名必须与以下一项匹配:</p>
153
154<ul>
155<li><code>public MyController(Context context, String key) {}</code></li>
156<li><code>public MyController(Context context) {}</code></li>
157</ul>
158
159<p>在为片段安装偏好设置时,信息中心会提供一种在显示之前附加 <code>PreferenceController</code> 的方法。在安装时,控制器会连接到片段,以便将来的所有相关事件均发送到控制器。</p>
160
161<code>DashboardFragment</code> 会在屏幕中保留 <code>PreferenceController</code> 的列表。在片段的 <code>onCreate()</code> 中,将为 <code>getAvailabilityStatus()</code> 方法调用所有控制器,如果它返回 true,则会调用 <code>displayPreference()</code> 来处理显示逻辑。
162<code>getAvailabilityStatus()</code> 也很重要,用于在搜索期间告诉“设置”框架哪些项可用。<p></p>
163
164<h4>Android 8.x 版本中的 PreferenceController</h4>
165
Android Partner Docs362780b2018-01-08 12:53:50 -0800166<p>
Android Partner Docsc331c4c2018-11-09 09:43:40 -0800167<code>PreferenceController</code> 包含与偏好设置进行交互所需的所有逻辑,包括显示、更新、编入搜索索引等。
Android Partner Docs362780b2018-01-08 12:53:50 -0800168</p>
169
170<p>
Android Partner Docsc331c4c2018-11-09 09:43:40 -0800171与偏好设置交互相对应,<code>
172PreferenceController</code> 的接口具有 <code>isAvailable()</code><code>
173displayPreference()</code><code>handlePreferenceTreeClicked()</code> 等 API。有关每个 API 的详细文档位于相应的接口类中。
Android Partner Docs362780b2018-01-08 12:53:50 -0800174</p>
175
176<p>
Android Partner Docsc331c4c2018-11-09 09:43:40 -0800177在为片段安装偏好设置时,信息中心会提供一种在显示之前附加 <code>PreferenceController</code> 的方法。在安装时,控制器会连接到片段,以便将来的所有相关事件均发送到控制器。
Android Partner Docs362780b2018-01-08 12:53:50 -0800178</p>
179
180<p>
Android Partner Docsc331c4c2018-11-09 09:43:40 -0800181<code>DashboardFragment</code> 会在屏幕中保留 <code>PreferenceControllers
182</code> 的列表。在片段的 <code>onCreate()</code> 中,将为 <code>isAvailable()</code> 方法调用所有控制器,如果它返回 true,则会调用 <code>displayPreference()</code> 来处理显示逻辑。
Android Partner Docs362780b2018-01-08 12:53:50 -0800183</p>
184
185<h2 id="using-dashboardfragment">使用 DashboardFragment</h2>
186
187<h3 id="moving-preference">将偏好设置从页面 A 移到页面 B</h3>
188
189<p>
Android Partner Docsc331c4c2018-11-09 09:43:40 -0800190如果偏好设置以静态方式列在原始页面的偏好设置 XML 文件中,请按照下面适用于您的 Android 版本的<strong>静态</strong>移动程序进行操作。否则,请按照适合您的 Android 版本的<strong>动态</strong>移动程序进行操作。
Android Partner Docs362780b2018-01-08 12:53:50 -0800191</p>
192
Android Partner Docsc331c4c2018-11-09 09:43:40 -0800193<h4 id="static-move-p">Android 9 中的静态移动</h4>
Android Partner Docs362780b2018-01-08 12:53:50 -0800194
195<ol>
Android Partner Docsc331c4c2018-11-09 09:43:40 -0800196<li>查找原始页面和目标页面的偏好设置 XML 文件。您可以从页面的 <code>getPreferenceScreenResId()</code> 方法中找到此信息。</li>
197<li>从原始页面的 XML 中移除偏好设置。</li>
Android Partner Docs362780b2018-01-08 12:53:50 -0800198<li>将偏好设置添加到目标页面的 XML 中。</li>
Android Partner Docsc331c4c2018-11-09 09:43:40 -0800199<li>从原始页面的 Java 实现中移除该偏好设置的 <code>PreferenceController</code>。它通常位于 <code>createPreferenceControllers()</code> 中。控制器可能是在 XML 中直接声明的。
200<p><strong>注意</strong>:偏好设置可能没有 <code>PreferenceController</code></p></li>
201<li>在目标页面的 <code>createPreferenceControllers()</code> 中实例化 <code>PreferenceController</code>。如果 <code>PreferenceController</code> 是在旧版页面的 XML 中定义的,则还要在新页面的 XML 中定义它。</li>
Android Partner Docs362780b2018-01-08 12:53:50 -0800202</ol>
203
Android Partner Docsc331c4c2018-11-09 09:43:40 -0800204<h4 id="dynamic-move">Android 9 中的动态移动</h4>
Android Partner Docs362780b2018-01-08 12:53:50 -0800205
206<ol>
207<li>查找原始页面和目标页面托管的类别。您可以在 <code>DashboardFragmentRegistry</code> 中找到此信息。</li>
Android Partner Docsc331c4c2018-11-09 09:43:40 -0800208<li>打开您需要移动的设置所在的 <code>AndroidManifest.xml</code> 文件,并找到代表此设置的 Activity 条目。</li>
209<li>将该 Activity 的 <code>com.android.settings.category</code> 元数据值设为新页面的类别键。</li>
210</ol>
211
212<h4 id="static-move-8">Android 8.x 版本中的静态移动</h4>
213
214<ol>
215<li>查找原始页面和目标页面的偏好设置 XML 文件。</li>
216您可以从页面的 <code>getPreferenceScreenResId()
217</code> 方法中找到此信息。
218<li>从原始页面的 XML 中移除偏好设置。</li>
219<li>将偏好设置添加到目标页面的 XML 中。</li>
220<li>在原始页面的 Java 实现中移除该偏好设置的 <code>PreferenceController</code>。它通常位于 <code>getPreferenceControllers()</code> 中。</li>
221<p><strong>注意</strong>:偏好设置可能没有 <code>PreferenceController</code></p>
222<li>在目标页面的 <code>getPreferenceControllers()</code> 中实例化 <code>PreferenceController</code></li>
223</ol>
224
225<h4 id="dynamic-move">Android 8.x 版本中的动态移动</h4>
226
227<ol>
228<li>查找原始页面和目标页面托管的类别。您可以在 <code>DashboardFragmentRegistry</code> 中找到此信息。</li>
229<li>打开您需要移动的设置所在的 <code>AndroidManifest.xml</code> 文件,并找到代表此设置的 Activity 条目。</li>
230<li>更改该 Activity 的 <code>com.android.settings.category</code> 元数据值,将值设为指向新页面的类别键。</li>
Android Partner Docs362780b2018-01-08 12:53:50 -0800231</ol>
232
233<h3 id="creating-a-new-preference">在页面中创建新的偏好设置</h3>
234
235<p>
Android Partner Docsc331c4c2018-11-09 09:43:40 -0800236如果偏好设置以静态方式列在原始页面的偏好设置 XML 文件中,请按照下面的<strong>静态</strong>程序进程操作。否则,请按照<strong>动态</strong>程序进行操作。
Android Partner Docs362780b2018-01-08 12:53:50 -0800237</p>
238
Android Partner Docsc331c4c2018-11-09 09:43:40 -0800239<h4 id="static-create">创建静态偏好设置</h4>
Android Partner Docs362780b2018-01-08 12:53:50 -0800240
241<ol>
242<li>找到页面的偏好设置 XML 文件。您可以从页面的 getPreferenceScreenResId() 方法中找到此信息。</li>
Android Partner Docsc331c4c2018-11-09 09:43:40 -0800243<li>在 XML 中添加一个新的偏好设置项。确保它具有独一无二的 <code>android:key</code></li>
244<li>在页面的 <code>getPreferenceControllers()</code> 方法中为该偏好设置定义一个 <code>PreferenceController</code>
245<ul>
246<li>在 Android 8.x 和 Android 9(选做)内,在页面的 <code>createPreferenceControllers()</code> 方法中为该偏好设置实例化一个 <code>PreferenceController</code>
247
248<p>如果该偏好设置已存在于其他地方,则可能已具有针对它的 <code>PreferenceController</code>。您可以重复使用该 <code>PreferenceController</code>,而无需构建新的。</p>
249</li>
250<li>从 Android 9 开始,您可以选择在偏好设置旁的 XML 中声明 <code>PreferenceController</code>。例如:
251<pre class="prettyprint">
252&lt;Preference
253 android:key="reset_dashboard"
254 android:title="@string/reset_dashboard_title"
255 <b>settings:controller="com.android.settings.system.ResetPreferenceController"/&gt;</b>
256</pre>
257</li>
258</ul>
259</li>
Android Partner Docs362780b2018-01-08 12:53:50 -0800260</ol>
261
Android Partner Docsc331c4c2018-11-09 09:43:40 -0800262<h4 id="dynamic-create">创建动态偏好设置</h4>
Android Partner Docs362780b2018-01-08 12:53:50 -0800263
264<ol>
265<li>查找原始页面和目标页面托管的类别。您可以在 <code>DashboardFragmentRegistry</code> 中找到此信息。</li>
Android Partner Docsc331c4c2018-11-09 09:43:40 -0800266<li><code>AndroidManifest</code> 中创建一个新的 Activity。</li>
267<li>向新 Activity 添加必要的元数据,以定义设置。将 <code>com.android.settings.category</code> 的元数据值设为第 1 步中定义的相同值。</li>
Android Partner Docs362780b2018-01-08 12:53:50 -0800268</ol>
269
Android Partner Docsc331c4c2018-11-09 09:43:40 -0800270<h3 id="create-new-page">创建新页面</h3>
Android Partner Docs362780b2018-01-08 12:53:50 -0800271<ol>
Android Partner Docsc331c4c2018-11-09 09:43:40 -0800272<li>创建一个继承自 <code>DashboardFragment</code> 的新片段。</li>
Android Partner Docs362780b2018-01-08 12:53:50 -0800273<li><code>DashboardFragmentRegistry</code> 中定义其类别。
274<p class="note"><strong>注意</strong>:此步骤是可选的。如果您在此页面中不需要任何动态偏好设置,则不需要提供类别键。</p></li>
Android Partner Docsc331c4c2018-11-09 09:43:40 -0800275<li>按照为此页面添加所需设置的步骤进行操作。要了解详情,请参阅<a href="#implementation">实现</a>部分。</li>
Android Partner Docs362780b2018-01-08 12:53:50 -0800276</ol>
277
278<h2 id="validation">验证</h2>
279
280<ul>
Android Partner Docsc331c4c2018-11-09 09:43:40 -0800281<li>在“设置”部分运行 robolectric 测试。应通过所有现有测试和新测试。
Android Partner Docs964c5952019-01-25 14:26:34 -0800282</li><li>编译并安装“设置”,然后手动打开正在修改的页面。该页面应该会立即更新。</li>
Android Partner Docs362780b2018-01-08 12:53:50 -0800283</ul>
284
285</body></html>