前面简单描述下了Preference的家族构成和基本知识,相信对于Preference早已不会陌生,肯定也跃跃欲试了吧,这篇文章就给大家总结下Preference、PreferenceActivity、PreferenceGroup、RingtonePreference的普通应用和管理,还有通过一些测试来验证一些机制和原理。
PreferenceActivity是一个抽象类,继承于ListActivity,以列表形式视图来展现界面,加载的整个View也是基于ListActivity中那个ListView的,其最主要的优势在于添加Preference后可让其状态持久化储存(通过SharedPreferences,一般存储在/data/data//shared_prefs文件夹下的默认名为“app package name”+”_preferences.xml”的文件里),比如说用户勾选CheckBox后退出应用,下一次进入到这一界面时候,对应的是CheckBox依然是被勾选状态,如果要实现这样的机制,我们自己也可以实现,但是没有必要,因为Android已经替我们实现了,就是我们的这一系列的主角——Preference,Preference会自动地替我们去保存这些状态对应的值到对应的SharedPreferences文件里,而当我们每次启动的时候Acitivity(PreferenceActivity)会自动根据key去获取相关数据,完成用户界面的更新。我们手机当中的系统设置就是及其典型的Preference的应用,也正是由于工作中需要去客制化Settings,才有了这一系列的文章。
上图是我们定制的Settings模块中的对应的部分SharedPreferences。关于Preference对应的SharedPreferences往往很容易被我们忽视两点
并非我们第一次打开相应界面之后就会自动创建对应的SharedPreferences文件,而是在我们改变了原有状态时候<喎�"/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPjwvcD4NCjxwPjxzdHJvbmc+sqK3x8v509C1xFByZWZlcmVuY2W8sMbk19PA4La8u+G0tL2oo6y99r321eu21NDo0qq8x8K817TMrLXEUHJlZmVyZW5jZTwvc3Ryb25nPqGjPC9wPg0KPGgyIGlkPQ=="2preferenceactivity的初始化">2、PreferenceActivity的初始化
PreferenceActivity其实和普通的Activity本质上来说区别不大,只不过多了些自动去读取SharedPrefrences的值来更新界面和其他一些逻辑,所以初始化本质上来说并无很大的区别,但是与普通Activity的layout不同,PreferenceActivity的layout我们可以理解成为两个部分:其他View和一个id为android.R.id.list的ListView,那么我们可以理解成为当我们在onCreate方法里先调用setContentView完成整个Activity的View的构建(layout文件里必须包含id为android.R.id.list的listView,否则会报E/AndroidRuntime: Caused by: java.lang.RuntimeException: Your content must have a ListView whose id attribute is ‘android.R.id.list’),再调用addPreferencesFromResource来完成Preference界面的构建;当然也可以只调用addPreferencesFromResource方法。
1
2
3
4
5
6
7
8
9
` `public` `class` `MainActivity` `extends` `PreferenceActivity {`
`@Override`
`protected` `void` `onCreate(Bundle savedInstanceState) {`
`super` `.onCreate(savedInstanceState);`
`setContentView(R.layout.activity_main);`
`addPreferencesFromResource(R.xml.demo_preference);`
`}`
`...`
`}
在res文件夹下新建xml文件夹,再在xml文件中新建对应的xml资源,xml资源类似我们在使用普通Activity时的layout文件,PreferenceActivity独特之处在于并不是使用普通的layout文件,而是使用res下xml文件夹下的xml资源文件
res/xml/demo_preference.xml
1
2
3
4
<!--?xml version=` `"1.0"` `encoding=` `"utf-8"` `?-->`
`<preferencescreen xmlns:android=` `"[http://schemas.android.com/apk/res/android](http://schemas.android.com/apk/res/android)"` `>`
`<checkboxpreference android:key=` `"key_checkbox_preference"` `android:summary=` `"Some summay for CheckBoxPreference"` `android:title=` `"The Title Of CheckBoxPreference"` `>`
`</checkboxpreference></preferencescreen>
也可通过代码去构造对象,添加容器之后再调用setPreferenceScreen(PreferenceScreen preferenceScreen)把容器对象设置到Activity上
1
2
3
4
5
6
7
8
9
` `private` `void` `createPreference(){`
`PreferenceScreen preferenceScreen =` `this` `.getPreferenceManager().createPreferenceScreen(` `this` `);` `//先构建PreferenceScreen对象得到一个布局容器`
`this` `.setPreferenceScreen(preferenceScreen);` `//设置容器`
`CheckBoxPreference checkBoxPreference=` `new` `CheckBoxPreference(` `this` `);` `//构建一个子Preference,待添加到容器中`
`checkBoxPreference.setKey(CHECKBOXPRERENCE_KEY);` `//设置key`
`checkBoxPreference.setTitle(` `"The Title Of CheckBoxPreference"` `);` `//设置title`
`checkBoxPreference.setSummary(` `"Some summay for CheckBoxPreference"` `);`
`preferenceScreen.addPreference(checkBoxPreference);` `//添加到容器中`
`}
前一篇文章我们讲述了Preference家族的基类(接下来我们所要介绍的其他子类Preference一定是继承了他的所有属性也可以理解成都是在继承他所展示的UI效果及交互功能的基础上升级的)而且Preference可以实例化,那么我们就可以把他看成对应的一个组件,其实和我们熟悉的TextView一样,所以我们需要使用的时候第一步肯定是先得到他的对象——而构造对象我们都可以通过两种方式:通过其对应的构造方法或者其他方法和通过xml映射(或许说法不够准确),接着第二步PreferenceActivity的初始化,再接着根据业务设置相关监听。
前面Android进阶——Preference详解之初识Preference及Preference系(一)已经讲过PreferenceScreen只能作为top-level节点,而构造对象我们都可以通过两种方式:通过其对应的构造方法或者其他方法和通过映射xml(或者讲法不够准确)。
res/xml/test_preference.xml
1
2
3
4
<!--?xml version=` `"1.0"` `encoding=` `"utf-8"` `?-->`
`<preferencescreen android:key=` `"using_categories_in_root_screen"` `android:summary=` `"Using Preference Categories"` `android:title=` `"Categories"` `xmlns:android=` `"[http://schemas.android.com/apk/res/android](http://schemas.android.com/apk/res/android)"` `>`
`<preference android:key=` `"key_prerence"` `android:summary=` `"Preference Demo"` `android:title=` `"Preferece"` `>`
`</preference></preferencescreen>
常见的Preference的事件有两个:setOnPreferenceClickListener和onPreferenceChange
设置Preference点击监听
1
2
3
4
5
6
7
preference.setOnPreferenceClickListener(` `new` `Preference.OnPreferenceClickListener() {`
`@Override`
`public` `boolean` `onPreferenceClick(Preference preference) {`
`//当接收到Click事件之后触发`
`return` `true` `;`
`}`
`});
设置Preference对应的SharedPrefernces值监听
1
2
3
4
5
6
7
preference.setOnPreferenceChangeListener(` `new` `Preference.OnPreferenceChangeListener() {`
`@Override`
`public` `boolean` `onPreferenceChange(Preference preference, Object newValue) {`
`//如果值改变了我们可以通过监听这个事件来处理`
`return` `true` `;`
`}`
`});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
` `@Override`
`protected` `void` `onCreate(Bundle savedInstanceState) {`
`super` `.onCreate(savedInstanceState);`
`setContentView(R.layout.activity_main);` `//activity_main里必须存在id为android.R.id.list的ListView否则报E/AndroidRuntime: Caused by: java.lang.RuntimeException: Your content must have a ListView whose id attribute is 'android.R.id.list'`
`addPreferencesFromResource(R.xml.test_preference);`
`mContext=getApplicationContext();`
`preference=findPreference(PREFERENCE_KEY);`
`preference.setOnPreferenceChangeListener(` `new` `Preference.OnPreferenceChangeListener() {`
`@Override`
`public` `boolean` `onPreferenceChange(Preference preference, Object newValue) {`
`//如果值改变了我们可以通过监听这个事件来获取新值`
`Toast.makeText(mContext, String.format(` `"Preference的值为%s"` `, newValue),Toast.LENGTH_LONG).show();`
`return` `true` `;`
`}`
`});`
`//设置Preference的点击事件监听`
`preference.setOnPreferenceClickListener(` `new` `Preference.OnPreferenceClickListener() {`
`@Override`
`public` `boolean` `onPreferenceClick(Preference preference) {`
`//当接收到Click事件之后触发`
`Toast.makeText(mContext,` `"Preference Clicked"` `,Toast.LENGTH_LONG).show();`
`return` `true` `;`
`}`
`});`
`}
xml属性
说明
android:icon
Preference的icon
android:summary
副标题、说明(小字体显示)
android:title
标题
android:key
对应的SharedPrefrences的key值
android:layout
PreferenceActivity的布局文件即如果设置了这个属性则会覆盖原来的UI
android:fragment
应用在PreferenceActivity中时,当用户点击这个Preference时,启动一个新的Fragment
android:enabled
设置Preference是否可用,false阴影状态不可操作
android:order
Preference的排序,整数类型如”100”
android:persistent
true时,系统会帮助我们去保存该设置,即使重启后依然能记忆之前的设置,这也是所谓的持久化 。这里 将 android:persistent设置为False,表明不需要让系统去做持久化,开发者系统通过自己的方式去实现持久化。
android:selectable
Preference是否可选,false可以点击但无响应
android:shouldDisableView
当View disabled的时候是否Preference也一样Disabled.
android:widgetLayout
自定义Preference用到给子Preference定义布局。
1
2
3
4
5
6
7
8
<!--?xml version=` `"1.0"` `encoding=` `"utf-8"` `?-->`
`<preferencescreen android:title=` `"PreferenceScreen"` `xmlns:android=` `"[http://schemas.android.com/apk/res/android](http://schemas.android.com/apk/res/android)"` `>`
`<preferencecategory android:key=` `"key_prerence"` `android:summary=` `"Preference Categories Summary"` `android:title=` `"Preference Categories"` `>`
`<checkboxpreference android:icon=` `"@mipmap/ic_launcher"` `android:key=` `"key_chkpreference"` `android:summary=` `"CheckboxPreference summary"` `android:title=` `"CheckBoxPreferenceCheckBoxPreferenceCheckBoxPreferenceCheckBoxPreference"` `>`
`<preference android:icon=` `"@mipmap/ic_red_launcher"` `android:key=` `"key_pre"` `android:layout=` `"@layout/activity_main"` `android:title=` `"Preference"` `>`
`<edittextpreference android:icon=` `"@mipmap/ic_blue_launcher"` `android:key=` `"key_edtkpreference"` `android:summary=` `"EditPreference summary"` `android:title=` `"EditPreference"` `>`
`</edittextpreference></preference></checkboxpreference></preferencecategory>`
`</preferencescreen>
在xml文件的Preference标签中,我们可以添加intent来为我们快速实现一种意图,比如说快速打开一个网页,或者快速启动一个Activity等等,还可以使用extra给intent标签加参数来传递参数(再通过getIntent().getStringExtra(“key”)来获取)。
点击这个Preference则会自动去调用浏览器打开http://www.hao123.com网页
1
2
3
4
5
<preference android:key=` `"key_pref_intent"` `android:title=` `"Click me open the web"` `>`
`<intent android:action=` `"android.intent.action.VIEW"` `android:data=` `"[http://www.hao123.com](http://www.hao123.com/)"` `>`
`<!--可以通过<extra>传附加信息getIntent().getStringExtra(` `"reused_key"` `) -->`
`<extra android:name=` `"key"` `android:value=` `"value"` `>`
`</extra></intent></preference>
启动指定类
1
2
3
4
5
6
<preference android:title=` `"PREFERENCE TITLE"` `>`
`<!-- android:targetPackage是应用程序的包名,而android:targetClass的路径在子包下的类 -->`
`<!-- android:targetPackage设置为子包,运行时则找不到Activity -->`
`<intent android:action=` `"ACTION_A_INTENT"` `android:targetclass=` `"com.crazy.training.ui.MainActivity"` `android:targetpackage=` `"com.crazy.training"` `>`
`</intent>`
`</preference>
PreferenceScreen和PreferenceCategory没有新增的属性,所有属性全部继承自Preference。其中PreferenceScreen作为顶级容器,PreferenceCategory作为次级容器(类似于SQL Group by功能暂且这么理解吧),虽然他们也是可以单独使用的,但是并不能响应onPreferenceClick和onPreferenceChange事件。
布局和MainActivity的代码依然很简单和前面类似
1
2
3
4
5
<!--?xml version=` `"1.0"` `encoding=` `"utf-8"` `?-->`
`<preferencescreen android:title=` `"PreferenceScreen"` `xmlns:android=` `"[http://schemas.android.com/apk/res/android](http://schemas.android.com/apk/res/android)"` `>`
`<preferencecategory android:key=` `"key_prerence"` `android:summary=` `"Preference Categories Summary"` `android:title=` `"Preference Categories"` `>`
`</preferencecategory>`
`</preferencescreen>
1
2
3
4
5
6
7
<!--?xml version=` `"1.0"` `encoding=` `"utf-8"` `?-->`
`<preferencescreen android:title=` `"PreferenceScreen"` `xmlns:android=` `"[http://schemas.android.com/apk/res/android](http://schemas.android.com/apk/res/android)"` `>`
`<preferencecategory android:key=` `"key_prerence"` `android:summary=` `"Preference Categories Summary"` `android:title=` `"Preference Categories"` `>`
`<checkboxpreference android:icon=` `"@mipmap/ic_launcher"` `android:key=` `"key_chkpreference"` `android:summary=` `"CheckboxPreference summary"` `android:title=` `"CheckBoxPreference"` `>`
`<edittextpreference android:icon=` `"@mipmap/ic_blue_launcher"` `android:key=` `"key_edtkpreference"` `android:summary=` `"EditPreference summary"` `android:title=` `"EditPreference"` `>`
`</edittextpreference></checkboxpreference></preferencecategory>`
`</preferencescreen>
RingtonePreference起作用就是供我们选择系统铃声的,除了Preference共有的属性外还新增了自己的几个独特属性。
新增属性
说明
android:ringtoneType
铃声类型:ringtone、notification、all、alarm
android:showDefault
布尔值是否显示默认铃声
android:showSilent
布尔值是否显示静音
应用也很简单,与Preference大同小异(注意看图)
1
2
3
4
5
<!--?xml version=` `"1.0"` `encoding=` `"utf-8"` `?-->`
`<preferencescreen android:key=` `"using_categories_in_root_screen"` `android:summary=` `"Using Preference Categories"` `android:title=` `"Categories"` `xmlns:android=` `"[http://schemas.android.com/apk/res/android](http://schemas.android.com/apk/res/android)"` `>`
`<ringtonepreference android:key=` `"key_prerence"` `android:summary=` `"RingPreference Summary"` `android:title=` `"RingPreferece Title"` `>`
`</ringtonepreference></preferencescreen>
Preference的管理主要包含Preference的创建、添加、移除和寻找特定Preference,Preference并没有直接提供相关替换的方法。
主要是通过各自对应Preference的构造方法或者直接在xml文件中定义来创建对应的Preference
添加只要是就是调用PreferenceGroup的addPreference(Preference preference)方法 来添加至容器PreferenceGroup。
对于PreferenceActivity的findPreference(key)方法,我们只需要知道key值就可以找到同一xml文件下相应的Preference,勿需考虑层级和嵌套关系
对于PreferenceGroup的removePreference(Preference preference)和removeAll()方法,都是针对某个PreferenceGroup来处理的,所以我们必须考虑层级嵌套关系,可以分为两步:先找到PreferenceGroup和要删除的Preference,再调用PreferenceGroup的removePreference执行删除动作。
首先这是我们的布局
1
2
3
4
5
6
7
8
9
<!--?xml version=` `"1.0"` `encoding=` `"utf-8"` `?-->`
`<preferencescreen android:key=` `"key_manage_prefs"` `xmlns:android=` `"[http://schemas.android.com/apk/res/android](http://schemas.android.com/apk/res/android)"` `>`
`<preferencecategory android:key=` `"key_category"` `android:title=` `"PreferenceCategory"` `>`
`<edittextpreference android:key=` `"key_edtprefs"` `android:title=` `"EditTextPreference"` `>`
`<preferencescreen android:key=` `"key_child_prefscreen"` `android:title=` `"Child PreferenceScreen"` `>`
`<checkboxpreference android:key=` `"key_checkbox"` `android:title=` `"CheckBoxPreference"` `>`
`</checkboxpreference></preferencescreen>`
`</edittextpreference></preferencecategory>`
`</preferencescreen>
测试主体代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
` `public` `class` `MainActivity` `extends` `PreferenceActivity {`
`private` `Context mContext;`
`private` `Preference preference;`
`@Override`
`protected` `void` `onCreate(Bundle savedInstanceState) {`
`super` `.onCreate(savedInstanceState);`
`addPreferencesFromResource(R.xml.test_preference);`
`//removePreferenceByKey();`
`mContext=getApplicationContext();`
`preference=findPreference(` `"key_checkbox_child"` `);` `//只要是同一个xml文件下的所有Preference都能通过key直接找到`
`preference.setOnPreferenceChangeListener(` `new` `Preference.OnPreferenceChangeListener() {`
`@Override`
`public` `boolean` `onPreferenceChange(Preference preference, Object newValue) {`
`Toast.makeText(mContext, String.format(` `"Preference的值为%s"` `, newValue),Toast.LENGTH_LONG).show();`
`return` `true` `;`
`}`
`});`
`preference.setOnPreferenceClickListener(` `new` `Preference.OnPreferenceClickListener() {`
`@Override`
`public` `boolean` `onPreferenceClick(Preference preference) {`
`Toast.makeText(mContext,` `"Preference Clicked"` `,Toast.LENGTH_LONG).show();`
`//getFragmentManager().beginTransaction().replace(android.R.id.content,new MainFragment()).commit();`
`return` `false` `;`
`}`
`});`
`}`
`private` `void` `removePreferenceByKey(){`
`/*PreferenceGroup preferenceGroup=(PreferenceGroup)findPreference("key_category");//先找到PreferenceGroup`
`Preference preference=findPreference("key_edtprefs");//再找到要删除的Preference*/`
`/*(PreferenceGroup)findPreference("key_child_prefscreen").removePreference(findPreference("key_checkbox_child"));//执行删除key为key_checkbox_child的Preference**/`
`getPreferenceScreen().removePreference(findPreference(` `"key_category"` `));` `//删除掉key_category及对应节点下的所有节点`
`//ERROR//getPreferenceScreen().removePreference(findPreference("key_edtprefs"));//无效,因为getPreferenceScreen获得的是当前的顶级容器,而key_edtprefs不是它的直接字节点`
`((PreferenceGroup)findPreference("key_category")).removeAll();//仅删除掉key_category下对应Preference节点下的所有子节点`
`}
这篇文章主要介绍了Preference家族树中顶级成员和次级成员的应用和简单原理的说明,也基本把几乎所有相关的知识点都涉及了,Preference的基本语法都是一样的,区别在于各自不同的特性。
手机扫一扫
移动阅读更方便
你可能感兴趣的文章