Preferences入门

来源:互联网 发布:板式家具用什么软件 编辑:程序博客网 时间:2024/05/14 10:32

概述

        在应用中经常会包含"设置"界面,该界面允许用户进行一些选择,从而更改应用的外观等。用户在"设置"界面更改之后的值通常保存在SharedPreferences中,但是如果自己通过代码实现的话,就得自己操作SP去存储。为了简化使用,可以使用Android自带的Preferences。虽然它内部使用的也是SP,但是不需要我们在用户更改设置后手动存储。

        与传统的界面相比,使用Preferences时也需要Activity,也需要写xml文件。但该xml文件并不是存储在res/layout下的,而是一定要存储在res/xml文件中。并且在创建界面时,并不是使用View及其子类,而是使用Preferences及其子类。

        每一个Preferences都需要一个键值对,这些键值对是存储在系统默认的SP中。当用户更改了相应的设置时,系统会自动更新默认的SP中的值。因此,在别处使用sp时取到的就是最新的值。

        为了使用Preferences,Activity必须继承PreferenceActivity(如果系统3.0以后,可使用PreferenceFragment)。常用的Preferences有EditTextPreference,CheckBoxPreference与ListPreference。如果界面展示的条目过多时,可以使用PreferenceCategory进行组或者使用PreferenceScreen进行分屏。

常用属性

        key:基本上所有的Preferences都需要。系统将数据存储到默认sp中时,就使用该属性的值做为sp中的key值。只有在下列三种情况下不需要该属性:1,节点为<PreferenceScreen>或者<PreferenceCategory>;2,当前的结点指定了<intent>属性;3,当前的结点通过一个Fragment展示时。

        title,summary:展示给用户的提示信息,相当于标题和副标题。

        defaultValue:默认值。如果用户没有修改该属性时,sp中存储的值。

常用Preferences

PreferenceScreen

        重新打开一个界面展示其包含的item。如:

    <PreferenceScreen        android:persistent="false"        android:title="PreferenceScreen" >        <Preference            android:key="button_voicemail_provider_key"            android:title="我好饿啊...." />        <PreferenceScreen            android:key="button_voicemail_setting_key"            android:persistent="false"            android:title="我非常的饿啊...." >            <Preference                android:key="button_voicemail_provider"                android:title="第二页我好饿啊....1" />            <Preference                android:key="button_voicemail_provider"                android:title="第二页我好饿啊....2" />        </PreferenceScreen>    </PreferenceScreen>
        在第一个界面中会有一个条目显示的文字是"PreferenceScreen"(因为外层的PreferenceScreen的title属性值是该值),点击该item时会重新打开一个界面。第二个界面上显示的就是"我好饿啊..."及"我非常的饿啊..."。当再点击"我非常的饿啊..."时又会显示一个界面,里面显示的就是"第二页xxxx"。

        从这可以看出,PreferenceScreen的title显示会展示在前一个界面中。当点击时,会启动一个新界面,新界面展示的内容便是PreferenceScreen所包含的内容

PreferenceCategory

        类似于PreferenceScreen,但不会启动新界面,它只是将item分组,并且每一个上面显示PreferenceCategory的title属性值。

CheckBoxPreference

        展示的item中含有一个checkbox,并且将boolean存储到sp中时(如果被选中存储的就是true)。

ListPreference

        打开一个单选对话框。它支持的类型(也就是能存储的数据类型)为:boolean,int,float,long以及String。

属性

        dialogTitle:显示的对话框的标题。

        entries:显示的对话框中的列表项。

        entryValues:当用户选择entries中某一项时,存储到sp中的值。

EditTextPreference

        打开一个只含有EditText的对话框,它只支持String类型。

常用操作

加载xml

        在activity继承PreferenceActivity后,重写onCreate()并调用addPreferencesFromResource()即可。示例:

public class PreferencesFromXml extends PreferenceActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        // Load the preferences from an XML resource        addPreferencesFromResource(R.xml.preferences);    }}

        也可以使用PreferenceFragment,定义好的PreferenceFragment就跟平时使用Fragment一样。示例如下:

public static class SettingsFragment extends PreferenceFragment {    @Override    public void onCreate(Bundle savedInstanceState) {//在onCreate中调用addPreferencesFromResource(0        super.onCreate(savedInstanceState);        // Load the preferences from an XML resource        addPreferencesFromResource(R.xml.preferences);    }}

获取存储的值

        存储时不需要通过代码进行操作,系统会自动存储到默认的sp中。因此,取值的时候只能从默认的sp中取。示例:

//获取默认的sp,得到是SharedPreferences对象mPreferences = PreferenceManager.getDefaultSharedPreferences(SecondActivity.this);if (mPreferences.contains("pref_sync")) {//从默认的sp中获取值boolean b = mPreferences.getBoolean("pref_sync", false);System.out.println("b = " + b);String string = mPreferences.getString("pref_syncConnectionType", "default");System.out.println(string);}

        在取值时,传入getXXX方法中的key值是定义在xml文件中的key属性的值。

打开新activity

        Preference结点下可以使用<intent>标签,通过该标签可以打开别的activity。如下:

    <Preference        android:title="打开第二个activity" >        <intent            android:targetClass="com.baigle.customview.SecondActivity"            android:data="xxdata"            android:targetPackage="com.baigle.customview" />    </Preference>

        <intent>标签下的android:action,android:mimeType与android:data分别相当于Intent.setAction(),Intent.setType()及Intent.setData()。

添加默认值

        虽然在xml文件中指定了defaultValue属性,但系统并不会在程序一运行时就将defaultValue存储到sp中,它只会在加载到关联该xml的界面时才会存储默认值。为此,可以在别的界面中调用PreferenceManager.setDefaultValues()提前将默认值存储到sp中

        该方法有三个参数,前两个不说,单说第三个,该参数表明是否可以重新将sp中的值还原成默认值。如果该值为true,那么无论何时调用该方法,都会将sp中的值还原成默认值,即使用户已经修改过。如果该值为false,则不会出现上述情况,故当第三个参数为false时,可以很安全地多次调用该方法。

        一般会在应用的入口activity的onCreate()中调用该方法,包括main Activity及别的可以进入到应用的activity。

保存

        当用户选择完毕时,需要将用户的选择进行保存。Preference有一系列persisXXX方法用于保存数据,只要在适合的地方保存就行。比如DialogPreference中的onDialogClosed()中。

        如果在Preference中获取保存的数据,可以通过getPersistedXXX系列方法进行获取

Preference Headers

概述

        在很多时候,可能需要一个界面展示列表。用户点击某个条目后才展示具体的设置。具体设置的展示方式有两种:如果屏幕不够宽就重新开启一个新屏幕;如果屏幕够宽,可以在屏幕的剩余部分展示。具体如下面的图(来自谷歌官方文档)



        为实现上述的情况,可以使用Preferences Header。虽然当屏幕不够宽的时候可以使用Preference Screen,但是没办法实现屏幕够宽时的要求。

步骤

        1,每一组设置都用一个PreferenceFragment。

        2,创建header文件,并且声明它所关联的PreferenceFragment。

        3,创建一个PreferenceActivity用来承载header文件,并且重写其中的onBuildHeaders()。此时不需要重写onCreate(),也不需要调用addPreferencesFromResource()。

示例

header文件

<preference-headers xmlns:android="http://schemas.android.com/apk/res/android" >    <header        android:fragment="com.baigle.customview.SecondFragment"        android:summary="Header1Summary"        android:title="Header1Title" >        <extra            android:name="someKey"            android:value="one" />    </header>    <header        android:fragment="com.baigle.customview.SecondFragment"        android:summary="Header2Summary"        android:title="Header2Title" >        <extra            android:name="someKey"            android:value="two" />    </header></preference-headers>
        header文件的根元素必须是preference-headers,每一个header元素都指向了一个item,并且通过header元素下的fragment属性指向了要展示的PreferenceFragment。

        header元素下的extra元素可以向关联的PreferenceFragment中传递数据。在上面的例子中,两个fragment属性指定的是同一个PreferenceFragment。但是可以通过extra元素中的value属性值使fragment加载不同的界面。
fragment示例如下:

public class SecondFragment extends PreferenceFragment {@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);String key = getArguments().getString("someKey");if ("one".equalsIgnoreCase(key)) {//根据value的值加载不同的xml文件addPreferencesFromResource(R.xml.preference_one);} else if ("two".equalsIgnoreCase(key)) {addPreferencesFromResource(R.xml.preference_two);}}}
承载header文件的activity示例如下:
public class MainActivity extends PreferenceActivity {//不需要重写onCreate(),只需要重写该方法即可public void onBuildHeaders(List<Header> target) {loadHeadersFromResource(R.xml.header_test, target);}}

兼容

        由于header是3.0以后引起来的,如果在3.0以前使用想使用类似于header,可以按以下方法进行。具体思路为:

利用Preference和intent元素模拟header效果。示例如下:

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >    <Preference        android:summary="Header1Summary"        android:title="Header1Title" >        <intent            android:action="one"            android:targetClass="com.baigle.customview.MainActivity"            android:targetPackage="com.baigle.customview" />    </Preference>    <Preference        android:summary="Header2Summary"        android:title="Header2Title" >        <intent            android:action="two"            android:targetClass="com.baigle.customview.MainActivity"            android:targetPackage="com.baigle.customview" />    </Preference></PreferenceScreen>
        这里面的intent元素始终指向同一个activity,只是每一次传递的action不同,这是为了在activity加载不同的preference XML,与<extra>中的value值不同是同一个目的。

承载的activity

public class MainActivity extends PreferenceActivity {private final String ACTION_ONE = "one";private final String ACTION_TWO = "two";@SuppressWarnings("deprecation")protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);System.out.println("oncreate。。。。");String action = getIntent().getAction();if (ACTION_ONE.equalsIgnoreCase(action)) {addPreferencesFromResource(R.xml.preference_one);} else if (ACTION_TWO.equalsIgnoreCase(action)) {addPreferencesFromResource(R.xml.preference_two);} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {addPreferencesFromResource(R.xml.header_legacy);}}@SuppressLint("NewApi")public void onBuildHeaders(List<Header> target) {loadHeadersFromResource(R.xml.header_test, target);}}
        与不兼容之前相比,重写了onCreate(),并在onCreate()中根据action和版本号加载不同的XML文件。同时也重写了onBuildHeaders()。

        由于onBuildHeaders()是3.0以后添加的,所以在3.0以前该方法不会被调用,只有3.0以后才会调用。同时在onCreate()中,当版本高于3.0时没有加载任何XML文件。这样就兼容了低版本与高版本:低于3.0时在onCreate()中加载了XML文件,此时不会执行onBuildHeaders();高于3.0时在onBuildHeaders加载xml文件,此时onCreate()中没有加载任何XML文件。这也是兼容低版本的一个方法:根据版本号不同,调用不同的方法

自定义

常用方法

        onCreateView():创建item显示界面。

        onBindView():为onCreateView()创建的界面绑定数据。比如采取一些XML文件中的title,summary之类的属性值,便设置到界面上。

        onClick():用来处理该条目的点击事件。如果想要执行onClick()方法,onCreateView()中的布局中的组件必须不能有焦点,也不能设置成clickable为true。

        onGetDefaultValue():主要用于获取默认值(android:defaultValue属性的值)。如果继承Preference时,该方法必须重写。它是在构造方法中调用的,因此该方法比onCreateView()与onBindView()先执行。如:

@Overrideprotected Object onGetDefaultValue(TypedArray a, int index) {defaultValue = a.getInt(index, DEFAULT_MIN);//直接使用a.get*()即可。return defaultValue;}
        onSetInitialValue():在该方法中主要可以做:将android:defaultValue属性的值存储到sp中,获取sp中存储的值(如果没有存储过,就显示android:defaultValue属性的值)方便初始化当前的显示。在onGetDefaultValue()后调用。

        当第一个参数为false时,第二个参数就是onGetDefaultValue()的返回值,因此可以在此时将android:defaultValue属性的值存储到sp中;第一个参数是true时,第二个参数为null。该方法有时候不执行,可能是因为onGetDefaultValue()返回的是null。如下:

@Overrideprotected void onSetInitialValue(boolean restorePersistedValue,Object defaultValue) {if (restorePersistedValue) {//为true时,就从sp中取出原来存储过的值mCurrentValue = this.getPersistedInt(mDefaultValue);} else {//将默认值设置成当前值。并且通过persist*()将默认值存储到sp中mCurrentValue = (Integer) defaultValue;persistInt(mCurrentValue);// 保存anddroid:defaultValue属性的值}}

继承DialogPreference

        虽然可以直接继承Preference,但是继承DialogPreference是一个更好的方法。它提供了一个item界面,并且当点击item时会弹出一个dialog。
        继承DialogPreference时,不需要重写上面三个方法,可以重写DialogPreference类中自身的三个方法,依次为:onCreateDialogView(),onBindDialogView()与onDialogClosed()。前两个方法类似于onCreateView()与onBindView(),最后一个方法是dialog关闭时用于保存数据的地方。不需要重写onClick()。
        对于onCreateDialogView()与onBindDialogView(),每一次弹出dialog时都会调用一次。
        onDialogClosed()中的参数表示用户是不是点击了"确定"按键,只有当点击的是确定时才需要保存数据,否则不需要。

自定义属性

        方法与自定义View时一样,使用的时候也一样。如下:

    <declare-styleable name="CustomPreference">        <attr name="maxValue" format="integer" />        <attr name="defaultValue" format="integer" />    </declare-styleable>

获取自定义属性值

        也与自定义View时一样,都是在构造方法中获取。如下:
public CustomPreference(Context context, AttributeSet attrs) {super(context, attrs);TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.CustomPreference);for (int x = 0; x < array.getIndexCount(); x++) {int index = array.getIndex(x);switch (index) {case R.styleable.CustomPreference_maxValue:maxValue = array.getInteger(index, DEFAULT_MAX);break;case R.styleable.CustomPreference_defaultValue:defaultValue = array.getInteger(index, DEFAULT_MIN);break;default:break;}}array.recycle();}

重写三个方法

/** * 创建dialog的content内容 */protected View onCreateDialogView() {//也可以直接在构造方法中调用setDialogLayoutResource()而不需要重写该方法mCurrentValue = getPersistedInt(defaultValue);final LayoutInflater layoutInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);final View layout = layoutInflater.inflate(R.layout.activity_second,null);return layout;}/** * 绑定数据 */protected void onBindDialogView(View view) {mCurrentValue = getPersistedInt(defaultValue);//获取已经存储的值final TextView tv_current = (TextView) view.findViewById(R.id.button1);SeekBar sb = (SeekBar) view.findViewById(R.id.button2);sb.setMax(maxValue);sb.setProgress(mCurrentValue);tv_current.setText(String.valueOf(mCurrentValue));sb.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {public void onStopTrackingTouch(SeekBar seekBar) {}public void onStartTrackingTouch(SeekBar seekBar) {}@Overridepublic void onProgressChanged(SeekBar seekBar, int progress,boolean fromUser) {tv_current.setText(String.valueOf(progress));mCurrentValue = progress;}});}/** * 当dialog关闭时会调用该方法,此时可以用于存储数据 */protected void onDialogClosed(boolean positiveResult) {if (positiveResult) {//为true时表示用户点击的是确定,所以保存数据;否则不保存persistInt(mCurrentValue);//保存当前的值}}

示例

<?xml version="1.0" encoding="utf-8"?><PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >    <CheckBoxPreference        android:defaultValue="true"        android:key="pref_sync"        android:summary="CheckBoxPreferenceSummary"        android:title="CheckBoxPreferenceTitle" />    <ListPreference        android:defaultValue="ListPreferenceDefaultValue"        android:dependency="pref_sync"        android:dialogTitle="ListPreferenceDialogTitle"        android:entries="@array/pref_syncConnectionTypes_entries"        android:entryValues="@array/pref_syncConnectionTypes_values"        android:key="pref_syncConnectionType"        android:title="ListPreferenceTitle" /></PreferenceScreen>
        与第一段代码对比着看,每一个<Preferences>节点指定的key属性的值就是getXXX()时的第一个参数的值。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 帮朋友代付在支付宝被骗怎么办 商家说未收到货拒绝退款怎么办 淘宝商家拒绝退款怎么办还没收货的 拼多多点错确认收货了怎么办 被别人用菜刀砍伤没钱看病怎么办 东京下了订单但不发货怎么办 绑定卷皮钱包的手机号码丢了怎么办 小孩回奶在垫的被子上发霉了怎么办 2个月宝宝不喝母乳只喝奶瓶怎么办 我的扣扣被盗了朋友别被骗了怎么办 我买的股票退市了我的钱怎么办啊 在美食林被门口买宝石的骗了怎么办 在商场买的彪马鞋子皮子裂了怎么办 手机换号了京东钱包里的余额怎么办 寄报销发票给顺丰快递搞丢了怎么办 物流显示揽件但把快递弄丢了怎么办 在李宁商城上买的东西丢了怎么办 我的货发物流都过了好几天怎么办 运动鞋子买小了一码有些挤脚怎么办 媳妇先动手打我我又打媳妇了怎么办 京东商城买个电视没验收破了怎么办 钱充给波克城市游戏还不能玩怎么办 我的魅族账号密保问题忘记了怎么办 在手机店买手机买贵了被骗了怎么办 信翼4g上网宝登录密码忘了怎么办 信翼4g上网宝管理密码忘了怎么办 淘宝上买了货但店铺消失了怎么办啊 微信的版本过低登陆不了微信怎么办 红米3用联通4g卡无信号怎么办 网店跟买家说好有货又没货怎么办 新买的号码被别人注册过微信怎么办 买了个号码卡已经被注册微信怎么办 我怎么办微信把拉黑一次删了人太多 国家大剧院的票丢了能补票吗怎么办 打完狂犬疫苗后我抽了很多烟怎么办 我老婆接受了我的小三现在该怎么办 今日头条我发的文章浏览量少怎么办 如果荷兰猪母的和公的打架该怎么办 我买的商铺地址被别人注册了怎么办 搜狗阅读购买搜豆没有到账该怎么办 捡的ⅴⅰⅴo指纹屏锁解不开怎么办