Settings 体系架构三 PreferenceFragment

PreferenceFragment,在整个Settings应用中,基本所有的页面都继承自它,比如DashboardFragment,它是大多数页面的父类。

PreferenceFragment将Preference显示成列表,Preference将自动保存到SharedPreferences中(如果Preference的persist设置为true的情况下)。调用PreferenceManager#getDefaultSharedPreferences()会自动生成对应的存储设置值的SharedPreferences,在该类中将使用这个SharedPreferences

PreferenceScreen应当作为root根元素容器,它里面包含了子PreferencePreferenceScreen有两种创建方式:

  • addPreferencesFromResource: 从xml资源文件中构建PreferenceScreen;
  • addPreferencesFromIntent: 通过在manifest中给Activity配置PreferenceManager#METADATA_KEY_PREFERENCES指向一个xml资源;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
* Adds preferences from activities that match the given {@link Intent}.
*/
public void addPreferencesFromIntent(Intent intent) {
requirePreferenceManager();
setPreferenceScreen(mPreferenceManager.inflateFromIntent(intent, getPreferenceScreen()));
}
/**
* Inflates the given XML resource and adds the preference hierarchy
* to the current preference hierarchy.
*/
public void addPreferencesFromResource(@XmlRes int preferencesResId) {
requirePreferenceManager();
setPreferenceScreen(mPreferenceManager.inflateFromResource(getActivity(),
preferencesResId, getPreferenceScreen()));
}
/**
* Sets the root of the preference hierarchy that this fragment is showing.
*/
public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
if (mPreferenceManager.setPreferences(preferenceScreen) && preferenceScreen != null) {
onUnbindPreferences();
mHavePrefs = true;
if (mInitDone) {
postBindPreferences(); /** 发送更新UI的消息 */
}
}
}

onCreateView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private int mLayoutResId = com.android.internal.R.layout.preference_list_fragment;
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
TypedArray a = getActivity().obtainStyledAttributes(null,
com.android.internal.R.styleable.PreferenceFragment,
com.android.internal.R.attr.preferenceFragmentStyle,
0);
mLayoutResId = a.getResourceId(com.android.internal.R.styleable.PreferenceFragment_layout,
mLayoutResId);
a.recycle();
return inflater.inflate(mLayoutResId, container, false);
}

onCreateView方法根据layoutId,加载View布局UI视图,该视图里面有一个ListView

更新UI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
private static final int MSG_BIND_PREFERENCES = 1;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_BIND_PREFERENCES:
bindPreferences();
break;
}
}
};
/** 发送更新UI的消息 */
private void postBindPreferences() {
if (mHandler.hasMessages(MSG_BIND_PREFERENCES)) return;
mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
}
/** 绑定界面,设置Adapter */
private void bindPreferences() {
final PreferenceScreen preferenceScreen = getPreferenceScreen();
if (preferenceScreen != null) {
View root = getView();
if (root != null) {
View titleView = root.findViewById(android.R.id.title);
if (titleView instanceof TextView) {
CharSequence title = preferenceScreen.getTitle();
if (TextUtils.isEmpty(title)) {
titleView.setVisibility(View.GONE);
} else {
((TextView) titleView).setText(title);
titleView.setVisibility(View.VISIBLE);
}
}
}
preferenceScreen.bind(getListView());
// bind视图,里面调用ListView.setAdapter...
}
onBindPreferences();
}

类关系

Struct

PreferenceScreen创建流程

PreferenceScreen_init

PreferenceScreen创建成功后,通过setPreferenceScreen最终会更新UI界面。