Android Preference 须知

Android Preference 须知

一、理论

 Android Preference 须知_第1张图片

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的子类们


Android Preference 须知_第2张图片

开关类型:

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文件,一个设置界面就完成了,上面的xml文件对应的界面如下:


Android Preference 须知_第3张图片

我们来分析一下这个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。

上述代码效果图如下:


Android Preference 须知_第4张图片

三、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);
 
    }
}


 

程序界面如下:

    

Android Preference 须知_第5张图片Android Preference 须知_第6张图片

点击“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)