Android Preference 须知

一、理论

 

1.前言

在Android的应用开发中经常会涉及到设置界面的设计开发,为此Android提供了名为Preference的设置处理机制,沿用这种机制的话能省去开发者很多不必要的时间开支。

那Preference究竟是什么呢?看一下你Android手机里的“设置”这个应用就知道了,大体界面如下:


这个设置界面就是通过Preference构建的,可能有些同学会说,这不就是一个普通的LinearLayout吗?有什么特别的?下面我们就开具体说说什么是Preference。

 

2.什么是Preference?

Preference翻译过来是“偏爱,爱好”的意思,在Android中Preference是一个具体的类,它代表着一个最基本的UI块(可以理解为ListView中的一个item),并且显示在Activity或Fragment内置的ListView上面,如图1-1中的“声音”选项,就是一个Preference的UI块表现(这里为什么要说表现呢?因为Preference本身并不是继承View的视图类,它只是代表着一个偏好选项然后通过提供UI块来展示这些偏好选项)。并且每一个UI块都会和一个SharePreferences关联来保存或恢复偏好设置。

 

3.Preference从何而来?

得到Preference的方法有两种:一种是从Xml文件中获取,在Xml文件中每一个节点都能指定特定的Preference的子类。另外一种方法就是在代码中动态的创建。为了处理好Preference与SharePreferences的关联,Preference类提供了一个Key来作为使用SharePreferences时的Key。


4.Preference的子类们



开关类型:

TwoStatePreference是一个抽象类,它下面的两个子类CheckBoxPreference和SwitchPreference。

 

弹出框类型:

弹出框类型的都继承子虚拟类DialogPreference,分别是EditPreference,MultiCheckPreference,ListPreference,MultiSelectListPreference,SeekBarDialogPreference,VolumePreferenc。

 

特殊:

RingtonePreference和SeekBarPreference分别是铃声选择和滑块。

 

组类型:

组类型都继承子抽象类PreferenceGroup,其中PreferenceCategory表示分类,PreferenceScreen主要用来表示一个设置界面中的根节点。


5.Preference其他相关类介绍:

GenericInflater:用于解析xml文件

 

PreferenceInflater:继承自GenericInflater用于解析包含Preference的xml

 

PreferenceActivity:在kk和之前的版本上用于显示一系列Preference的Header(标头,用于跳转到对应的PreferenceFragment),从L开始PreferenceActivity的功能被PreferenceFragment集成了。

 

PreferenceFragment:用ListView来显示一系列Preference的层次结构。

 

PreferenceManager:用于帮助从xml或代码中创建Preference的层次结构。


二、实践

 

1.从xml文件中构建Preference ,主要代码如下:

----PreferencesFromXml.java----

 @Override    protected void onCreate(BundlesavedInstanceState) {        super.onCreate(savedInstanceState);         // Load the preferences from an XMLresource        //这个方法在L上已经不被提倡使用        addPreferencesFromResource(R.xml.preferences);    } 

preferences文件内容如下:

<?xml version="1.0" encoding="utf-8"?>                                                                                                                                                                                                                                                                                  

 

就是这么简单,只需要简单配置一下xml文件,一个设置界面就完成了,上面的xml文件对应的界面如下:



我们来分析一下这个xml文件

首先看它的根节点 PreferenceScreen 它对应的就是PreferenceScreen对象表示这一层次结构的最外层。接着是PreferenceCategory它表示一个分类的开始对应PreferenceCategory对象。在PreferenceCategory里可以看到一些节点如:CheckBoxPreference,EditTextPreference,ListPreference等,都是表示一个设置选项,其对应的也是名字与之相同的类。

 

2.从代码中构建Preference

代码如下:

----PreferencesFromCode.java----

 

public classPreferencesFromCode extends PreferenceActivity {     private static final StringPARENT_CHECKBOX_PREFERENCE = "parent_checkbox_preference";     @Override    protected void onCreate(BundlesavedInstanceState) {        super.onCreate(savedInstanceState);         PreferenceScreen root =getPreferenceManager().createPreferenceScreen(this);        setPreferenceScreen(root);        populatePreferenceHierarchy(root);    }     private voidpopulatePreferenceHierarchy(PreferenceScreen root) {        // Inline preferences        PreferenceCategory inlinePrefCat = newPreferenceCategory(this);       inlinePrefCat.setTitle(R.string.inline_preferences);        root.addPreference(inlinePrefCat);         // Checkbox preference        CheckBoxPreference checkboxPref = newCheckBoxPreference(this);        checkboxPref.setKey("checkbox_preference");       checkboxPref.setTitle(R.string.title_checkbox_preference);       checkboxPref.setSummary(R.string.summary_checkbox_preference);       inlinePrefCat.addPreference(checkboxPref);         // Switch preference        SwitchPreference switchPref = newSwitchPreference(this);       switchPref.setKey("switch_preference");       switchPref.setTitle(R.string.title_switch_preference);       switchPref.setSummary(R.string.summary_switch_preference);        inlinePrefCat.addPreference(switchPref);         // Dialog based preferences        PreferenceCategory dialogBasedPrefCat =new PreferenceCategory(this);       dialogBasedPrefCat.setTitle(R.string.dialog_based_preferences);        root.addPreference(dialogBasedPrefCat);         // Edit text preference        EditTextPreference editTextPref = newEditTextPreference(this);       editTextPref.setDialogTitle(R.string.dialog_title_edittext_preference);       editTextPref.setKey("edittext_preference");        editTextPref.setTitle(R.string.title_edittext_preference);       editTextPref.setSummary(R.string.summary_edittext_preference);       dialogBasedPrefCat.addPreference(editTextPref);         // List preference        ListPreference listPref = newListPreference(this);       listPref.setEntries(R.array.entries_list_preference);       listPref.setEntryValues(R.array.entryvalues_list_preference);       listPref.setDialogTitle(R.string.dialog_title_list_preference);        listPref.setKey("list_preference");       listPref.setTitle(R.string.title_list_preference);       listPref.setSummary(R.string.summary_list_preference);       dialogBasedPrefCat.addPreference(listPref);         // Launch preferences        PreferenceCategory launchPrefCat = newPreferenceCategory(this);       launchPrefCat.setTitle(R.string.launch_preferences);        root.addPreference(launchPrefCat);         /*         * The Preferences screenPref serves asa screen break (similar to page         * break in word processing). Like forother preference types, we assign         * a key here so that it is able tosave and restore its instance state.         */        // Screen preference        PreferenceScreen screenPref =getPreferenceManager().createPreferenceScreen(this);       screenPref.setKey("screen_preference");       screenPref.setTitle(R.string.title_screen_preference);       screenPref.setSummary(R.string.summary_screen_preference);       launchPrefCat.addPreference(screenPref);         /*         * You can add more preferences toscreenPref that will be shown on the         * next screen.         */         // Example of next screen togglepreference        CheckBoxPreferencenextScreenCheckBoxPref = new CheckBoxPreference(this);       nextScreenCheckBoxPref.setKey("next_screen_toggle_preference");       nextScreenCheckBoxPref.setTitle(R.string.title_next_screen_toggle_preference);       nextScreenCheckBoxPref.setSummary(R.string.summary_next_screen_toggle_preference);        screenPref.addPreference(nextScreenCheckBoxPref);         // Intent preference        PreferenceScreen intentPref =getPreferenceManager().createPreferenceScreen(this);        intentPref.setIntent(newIntent().setAction(Intent.ACTION_VIEW)               .setData(Uri.parse("http://www.android.com")));       intentPref.setTitle(R.string.title_intent_preference);       intentPref.setSummary(R.string.summary_intent_preference);       launchPrefCat.addPreference(intentPref);         // Preference attributes        PreferenceCategory prefAttrsCat = newPreferenceCategory(this);       prefAttrsCat.setTitle(R.string.preference_attributes);        root.addPreference(prefAttrsCat);         // Visual parent toggle preference        CheckBoxPreference parentCheckBoxPref =new CheckBoxPreference(this);       parentCheckBoxPref.setTitle(R.string.title_parent_preference);       parentCheckBoxPref.setSummary(R.string.summary_parent_preference);        prefAttrsCat.addPreference(parentCheckBoxPref);       parentCheckBoxPref.setKey(PARENT_CHECKBOX_PREFERENCE);         // Visual child toggle preference        // See res/values/attrs.xml for the that defines        // TogglePrefAttrs.        TypedArray a = obtainStyledAttributes(R.styleable.TogglePrefAttrs);        CheckBoxPreference childCheckBoxPref =new CheckBoxPreference(this);       childCheckBoxPref.setTitle(R.string.title_child_preference);       childCheckBoxPref.setSummary(R.string.summary_child_preference);        childCheckBoxPref.setLayoutResource(               a.getResourceId(R.styleable.TogglePrefAttrs_android_preferenceLayoutChild,                        0));       prefAttrsCat.addPreference(childCheckBoxPref);        childCheckBoxPref.setDependency(PARENT_CHECKBOX_PREFERENCE);        a.recycle();    }}

 

动态构建Preference的过程是:构建PreferenceScreen,然后构建PreferenceCategory,并往PreferenceCategory中添加需要使用的Preference的子类,然后将PreferenceCategory添加到PreferenceScreen。

上述代码效果图如下:



三、Preference实现机制

 

在讲机制之前我们来做一个简单的demo,通过这个demo来直击Preference的运行现场。

 

demo很简单,有两个界面:

MyPreferenceDemo.java (一个activity,显示从SharePreferences取key为my_demo_key的值)

MySetting.java (一个key为my_demo_key的EditPreference)

关键代码如下:

----MyPreferenceDemo.java

public class MyPreferenceDemo extends Activity {     private TextView mTextView ;    @Override    protected void onCreate(BundlesavedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mTextView = (TextView)findViewById(R.id.show_preferecne) ;    }     @Override    protected void onResume() {        super.onResume();        mTextView.setText(getPreferenceByKey());    }     private String getPreferenceByKey() {               String pref = "" ;        pref =PreferenceManager.getDefaultSharedPreferences(this).getString("my_demo_key","Hello") ;        return pref;    }     @Override    public boolean onCreateOptionsMenu(Menu menu){        // Inflate the menu; this adds itemsto the action bar if it is present.        getMenuInflater().inflate(R.menu.main, menu);        return true;    }     @Override    public boolean onOptionsItemSelected(MenuItemitem) {        if(item.getItemId() == R.id.action_settings){            Toast.makeText(this, "settings", Toast.LENGTH_LONG).show() ;            Intent intent = new Intent() ;            intent.setClass(this, MySetting.class) ;            startActivity(intent) ;        }        return super.onOptionsItemSelected(item);    }}


 

----MySetting.java

public class MySetting extends PreferenceActivity {     @Override    protected void onCreate(BundlesavedInstanceState) {        super.onCreate(savedInstanceState);               PreferenceScreen root = getPreferenceManager().createPreferenceScreen(this);        setPreferenceScreen(root);        populatePreferenceHierarchy(root);    }       private void populatePreferenceHierarchy(PreferenceScreenroot) {        PreferenceCategory myCat = new PreferenceCategory(this);        myCat.setTitle("My PreferenceDemo");        root.addPreference(myCat);         EditTextPreference editTextPref = new EditTextPreference(this);        editTextPref.setDialogTitle("please inputsomething");        editTextPref.setKey("my_demo_key");        editTextPref.setTitle("settings");        editTextPref.setSummary("设置activity中需要显示的字符串");        myCat.addPreference(editTextPref);     }}


 

程序界面如下:

    


点击“settings”输入“这是preference的demo”,然后返回第一个界面,就会显示 “这是preference的demo”。

 

我们先来看看获得SharePreferences的这个方法:

 

PreferenceManager.getDefaultSharedPreferences(this)


跟进源代码发现getDefaultSharedPreferences的实现如下:

     public static SharedPreferencesgetDefaultSharedPreferences(Context context)      {        returncontext.getSharedPreferences(getDefaultSharedPreferencesName(context),               getDefaultSharedPreferencesMode());    }     private static StringgetDefaultSharedPreferencesName(Context context) {        return context.getPackageName() + "_preferences";    }     private static intgetDefaultSharedPreferencesMode() {        return Context.MODE_PRIVATE;    }

内部其实还是调用了 getSharedPreferences这个方法来获得SharePreferences,参数name和mode分别是:context.getPackageName() +"_preferences" Context.MODE_PRIVATE

 

接着我们看看我们使用的 EditTextPreference是怎么将字符串保存到SharePreferences的,

 

我们看到在EditTextPreference内部有这么一个回调方法:

 

  

 @Override    protected void onDialogClosed(boolean positiveResult) {        super.onDialogClosed(positiveResult);               if (positiveResult) {            String value = mEditText.getText().toString();            if (callChangeListener(value)) {                setText(value);            }        }    }

 

当设置好字符串关闭对话框时这个方法会被回调,获得输入的字符串value然后调用settext(value),

 

   

 public void setText(String text) {        final boolean wasBlocking =shouldDisableDependents();               mText = text;               persistString(text);               final boolean isBlocking =shouldDisableDependents();        if (isBlocking != wasBlocking) {            notifyDependencyChange(isBlocking);        }    }

 

我们接着看persistString(text);  这个方法,首先persist的意思是持久化,那我们可以很容易联想到本地文件或者数据库之类的,那这边到底会把text保存到哪里?我们接着看。

 

 

   protected boolean persistString(String value) {        if (shouldPersist()) {            // Shouldn't store null            if (value == getPersistedString(null)) {                // It's already there, so the sameas persisting                return true;            }                       SharedPreferences.Editor editor = mPreferenceManager.getEditor();            editor.putString(mKey, value);            tryCommit(editor);            return true;        }        return false;    }

 

看到这里就就明了了,最终还是将value这个数据保存在了SharePreferences里面。

 

最基本的Preference实现机制就到这里了,总结一句话:

Preference设置属性的保存还是依赖于SharePreferences

关于SharePreferences的运行机制,我会在后面在给出。


pdf下载 http://pan.baidu.com/s/1o6p2dYi

更多相关文章

  1. Android(安卓)Activity界面切换添加动画特效
  2. android EditText设置不可写
  3. Android(安卓)拨号器的简单实现
  4. android“设置”里的版本号
  5. android用户界面之按钮(Button)教程实例汇
  6. 锁屏界面
  7. 在Fragment中设置控件点击方法,执行失败。
  8. Android(安卓)闹钟管理类的使用
  9. Android设置通知栏/状态栏透明改变通知栏颜色和app最上部分颜色

随机推荐

  1. CentOS Mysql数据库如何实现定时备份
  2. mysql数据库是做什么的
  3. 删除mysql数据表如何操作
  4. mysql如何设置不区分大小写
  5. 验证mysql是否安装成功的方法
  6. sql与mysql有哪些区别
  7. mysql属于关系型数据库吗
  8. mysql数据库是做什么
  9. MySQL语句执行顺序和编写顺序实例解析
  10. linux环境下安装mysql数据库的详细教程