addPreferencesFromResource()方法在PreferenceActivity类和PreferenceFragment类(Android3.0以后才有)中都有实现,两个中内容是差不多的(只是PreferenceActivity中的参数this在PreferenceFragment中变成了getActivity(),这个我想大家都可以理解)。PreferenceActivity中方法体如下:
- /**
- * Inflates the given XML resource and addsthe preference hierarchy to the current
- * preference hierarchy.
- *
- * @param preferencesResId The XML resourceID to inflate.
- */
- public void addPreferencesFromResource(intpreferencesResId) {
- requirePreferenceManager()
- setPreferenceScreen(mPreferenceManager.inflateFromResource(this,
- preferencesResId,getPreferenceScreen()));
- }
- public PreferenceScreen inflateFromResource(Contextcontext, int resId,
- PreferenceScreen rootPreferences) {
- … …
- final PreferenceInflater inflater = newPreferenceInflater(context, this);
- rootPreferences = (PreferenceScreen)inflater.inflate(resId, rootPreferences, true);
- rootPreferences.onAttachedToHierarchy(this);
- … …
- return rootPreferences;
- }
下面来看setPreferenceScreen()方法,PreferenceFragment类和PreferenceActivity类的setPreferenceScreen()有一点点小区别,PreferenceActivity类的setPreferenceScreen()方法为当前屏幕设置了一个标题,而PreferenceFragment中没有(应该在某个地方已经默认将该PreferenceScreen的title设置为屏幕标题了),其他实现的功能都是一样的。下面来看PreferenceActivity类的setPreferenceScreen()方法体:
- public voidsetPreferenceScreen(PreferenceScreen preferenceScreen) {
- requirePreferenceManager();
- if(mPreferenceManager.setPreferences(preferenceScreen)
- && preferenceScreen != null) {
- postBindPreferences();
- CharSequence title = getPreferenceScreen().getTitle();
- // Setthe title of the activity
- if(title != null) {
- setTitle(title);
- }
- }
- }
- private void postBindPreferences() {
- if(mHandler.hasMessages(MSG_BIND_PREFERENCES)) return;
- mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
- }
- private void bindPreferences() {
- final PreferenceScreen preferenceScreen= getPreferenceScreen();
- if (preferenceScreen != null) {
- preferenceScreen.bind(getListView());
- … …
- }
- }
- public void bind(ListView listView) {
- listView.setOnItemClickListener(this);
- listView.setAdapter(getRootAdapter());
- onAttachedToActivity();
- }
- public ListAdapter getRootAdapter() {
- if (mRootAdapter == null) {
- mRootAdapter = onCreateRootAdapter();
- }
- return mRootAdapter;
- }
- protected ListAdapter onCreateRootAdapter() {
- return newPreferenceGroupAdapter(this);
- }
终于拨开层层云雾见晴天了。PreferenceScreen显示的适配器原来是一个PreferenceGroupAdapter对象。这里要注意的是,PreferenceGroupAdapter实现了OnPreferenceChangeInternalListener接口,其中有个方法onPreferenceHierarchyChange(),当有Preference添加或删除时都会调用该方法,故当Preference添加或删除需要做一些动作(如调整Preference背景等)时可在该方法中实现。就分析到这里了,想看具体显示就看该适配的getView()方法了,分析方法跟分析普通BaseAdapter子类没区别。反正最终会调用到Preference类的onCreateView()方法和onBindView()方法。
原文链接:http://blog.csdn.NET/vipclx/article/details/9002034
补充:
通过上面的讲解,我们知道各个preference被添加到ListView中,即Preference的显示以列表的形式展现给用户。那这个ListView在哪里设置并实例化的呢?而且,如果对Preference比较熟悉的话,我们知道ListView的id是“@Android:id/list”,这个又是怎么来呢。通过下面的代码可知,PreferenceActivity或者PreferenceFragment在实例化显示过程中会首先inflate一个包含listview(其id为@android:id/list)的Layout布局。inflate完成后,在上面的函数bindPreferences中调用getListView()可以获取此ListView实例。具体的代码逻辑如下:
在PreferenceActivity的onCreate()函数:
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(com.android.internal.R.layout.preference_list_content);
- }
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- return inflater.inflate(com.android.internal.R.layout.preference_list_fragment, container,
- false);
- }
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:background="@android:color/transparent"
- android:layout_removeBorders="true">
- <ListView android:id="@android:id/list"
- style="?attr/preferenceFragmentListStyle"
- android:layout_width="match_parent"
- android:layout_height="0px"
- android:layout_weight="1"
- android:paddingTop="0dip"
- android:paddingBottom="@dimen/preference_fragment_padding_bottom"
- android:scrollbarStyle="@integer/preference_fragment_scrollbarStyle"
- android:clipToPadding="false"
- android:drawSelectorOnTop="false"
- android:cacheColorHint="@android:color/transparent"
- android:scrollbarAlwaysDrawVerticalTrack="true" />
- <TextView android:id="@android:id/empty"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:padding="@dimen/preference_fragment_padding_side"
- android:gravity="center"
- android:visibility="gone" />
- ......
- </LinearLayout>
在实际的开发过程中,我们会遇到在同一个UI中显示Preference项和自定义的布局项的清形,如何实现呢。方法就是自定义Layout,用于显示定制化界面,并包含listview(其id为@android:id/list),用于显示Preference项;然后重载上面提到的函数onCreate()或者onCreateView(),并inflate自定义的Layout。以PreferenceActivity为例实现如下:
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- // set customize layout that contains listview
- setContentView(com.android.internal.R.layout.layout_customize_list;
- // Load the preferences from an XML resource
- addPreferencesFromResource(R.xml.preferences);
- ......
- }