Settings 体系架构一 Preference

Settings中的菜单项,都是基于Preference实现的,Preference提供了一个UI视图显示到Activity的ListView中,并且关联了一个SharedPreferences,用于存取Preference值。

使用Preference的时候,需要在XML中配置它,通常会继承Preference实现特定的页面或者功能,它还可以嵌套定义,就像View的嵌套一样。
该类包含了一个key,将用于SharedPreferences的key,用户可以决定怎么去存储值。

XML属性配置

  • android.R.styleable#Preference_icon: 左侧图标
  • android.R.styleable#Preference_key: 存储的Key
  • android.R.styleable#Preference_title: Title标题
  • android.R.styleable#Preference_summary: summary状态信息
  • android.R.styleable#Preference_order: 显示顺序
  • android.R.styleable#Preference_fragment:Fragment
  • android.R.styleable#Preference_layout: UI布局资源id
  • android.R.styleable#Preference_widgetLayout: Widget布局资源id,比如checkbox的图标布局
  • android.R.styleable#Preference_enabled: 启用/禁用状态,禁用后不响应点击事件
  • android.R.styleable#Preference_selectable: 是否可选
  • android.R.styleable#Preference_dependency: 依赖菜单项
  • android.R.styleable#Preference_defaultValue: 默认值
  • android.R.styleable#Preference_shouldDisableView: 禁用所有的子View当enabled为false时
  • android.R.styleable#Preference_recycleEnabled: 是否可重用该Preference的UI布局
  • android.R.styleable#Preference_singleLineTitle: 只显示单行标题
  • android.R.styleable#Preference_iconSpaceReserved: Icon不可见时,是否保留布局宽度
  • android.R.styleable#Preference_persistent: 是否永久保存值,默认值true,该key对应的值会被保存到Preferences中或者PreferenceDataStore中

源码分析

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
public class Preference implements Comparable<Preference> {
/**
* 存储数据的DataStore对象,如果为空时使用PreferenceManager#getPreferenceDataStore获取,
* 如果该方法也返回null,则表示使用SharedPreferences来存储值。
*/
@Nullable
private PreferenceDataStore mPreferenceDataStore;
/**
* Gets the View that will be shown in the {@link PreferenceActivity}.
*/
public View getView(View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = onCreateView(parent);
}
onBindView(convertView);
return convertView;
}
/**
* 创建UI布局,默认会根据mLayoutResId去从xml中加载布局。
*/
@CallSuper
protected View onCreateView(ViewGroup parent) {
final LayoutInflater layoutInflater =
(LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View layout = layoutInflater.inflate(mLayoutResId, parent, false);
final ViewGroup widgetFrame = (ViewGroup) layout
.findViewById(com.android.internal.R.id.widget_frame);
if (widgetFrame != null) {
if (mWidgetLayoutResId != 0) {
layoutInflater.inflate(mWidgetLayoutResId, widgetFrame);
} else {
widgetFrame.setVisibility(View.GONE);
}
}
return layout;
}
/**
* 绑定View和数据,
*/
@CallSuper
protected void onBindView(View view) {
final TextView titleView = view.findViewById(com.android.internal.R.id.title);
// 设置Title
if (titleView != null) {
final CharSequence title = getTitle();
if (!TextUtils.isEmpty(title)) {
titleView.setText(title);
titleView.setVisibility(View.VISIBLE);
if (mHasSingleLineTitleAttr) {
titleView.setSingleLine(mSingleLineTitle);
}
} else {
titleView.setVisibility(View.GONE);
}
}
final TextView summaryView = (TextView) view.findViewById(
com.android.internal.R.id.summary);
// 设置summary
if (summaryView != null) {
final CharSequence summary = getSummary();
if (!TextUtils.isEmpty(summary)) {
summaryView.setText(summary);
summaryView.setVisibility(View.VISIBLE);
} else {
summaryView.setVisibility(View.GONE);
}
}
final ImageView imageView = view.findViewById(com.android.internal.R.id.icon);
if (imageView != null) { // 设置Icon
if (mIconResId != 0 || mIcon != null) {
if (mIcon == null) {
mIcon = getContext().getDrawable(mIconResId);
}
if (mIcon != null) {
imageView.setImageDrawable(mIcon);
}
}
if (mIcon != null) {
imageView.setVisibility(View.VISIBLE);
} else {
imageView.setVisibility(mIconSpaceReserved ? View.INVISIBLE : View.GONE);
}
}
// ...
if (mShouldDisableView) {
setEnabledStateOnViews(view, isEnabled());
}
}
public void setOrder(int order) {
if (order != mOrder) {
mOrder = order;
// 设置顺序并重新排序列表
notifyHierarchyChanged();
}
}
/**
* 点击事件,它会保存值到SharedPreferences,子类覆写该方法调用callChangeListener(Object)
* 来确保客户端想要更新preference中的值为newValue。
*/
protected void onClick() {
}
/**
* 用户点击View后调用这个方法,此时value并未改变,客户端可以放弃掉此次修改值。
* @return True 如果客户端想保存这个值,则返回true。
*/
protected boolean callChangeListener(Object newValue) {
return mOnChangeListener == null || mOnChangeListener.onPreferenceChange(this, newValue);
}
public void performClick(PreferenceScreen preferenceScreen) {
if (!isEnabled()) {
return;
}
onClick();
if (mOnClickListener != null && mOnClickListener.onPreferenceClick(this)) {
return;
}
PreferenceManager preferenceManager = getPreferenceManager();
if (preferenceManager != null) {
PreferenceManager.OnPreferenceTreeClickListener listener = preferenceManager
.getOnPreferenceTreeClickListener();
if (preferenceScreen != null && listener != null
&& listener.onPreferenceTreeClick(preferenceScreen, this)) {
return;
}
}
if (mIntent != null) { // 如果mInten不为空,则启动Inent对应的Activity。
Context context = getContext();
context.startActivity(mIntent);
}
}
/**
* 根据Order进行排序,如果未指定Order,则根据Title进行排序。
*/
@Override
public int compareTo(Preference another) {
if (mOrder != another.mOrder) {
// Do order comparison
return mOrder - another.mOrder;
} else if (mTitle == another.mTitle) {
// If titles are null or share same object comparison
return 0;
} else if (mTitle == null) {
return 1;
} else if (another.mTitle == null) {
return -1;
} else {
// Do name comparison
return CharSequences.compareToIgnoreCase(mTitle, another.mTitle);
}
}
}