Android(安卓)Preference 须知
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
更多相关文章
- Android(安卓)Activity界面切换添加动画特效
- android EditText设置不可写
- Android(安卓)拨号器的简单实现
- android“设置”里的版本号
- android用户界面之按钮(Button)教程实例汇
- 锁屏界面
- 在Fragment中设置控件点击方法,执行失败。
- Android(安卓)闹钟管理类的使用
- Android设置通知栏/状态栏透明改变通知栏颜色和app最上部分颜色