Android PreferenceActivity 源码分析
PreferenceActivity 的继承关系,
public abstract class PreferenceActivity extends ListActivity implements
PreferenceManager.OnPreferenceTreeClickListener,
PreferenceFragment.OnPreferenceStartFragmentCallback {
。。。
}
从上面可以看出,preferenceActivity 其实是listActivity。
onCreate 初始关布局
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Theming for the PreferenceActivity layout and for the Preference Header(s) layout
TypedArray sa = obtainStyledAttributes(null,
com.android.internal.R.styleable.PreferenceActivity,
com.android.internal.R.attr.preferenceActivityStyle,
0);
final int layoutResId = sa.getResourceId(
com.android.internal.R.styleable.PreferenceActivity_layout,
com.android.internal.R.layout.preference_list_content);
mPreferenceHeaderItemResId = sa.getResourceId(
com.android.internal.R.styleable.PreferenceActivity_headerLayout,
com.android.internal.R.layout.preference_header_item);
mPreferenceHeaderRemoveEmptyIcon = sa.getBoolean(
com.android.internal.R.styleable.PreferenceActivity_headerRemoveIconIfEmpty,
false);
sa.recycle();
setContentView(layoutResId);
...
Activity 在oncreate 时,先将com.android.internal.R.layout.preferenc_list_content 作为默认的layout。
layout的具体定义如下:
addPreferencesFromResource
@Deprecated
public void addPreferencesFromIntent(Intent intent) {
if (DBG) {
Log.d(TAG, "addPreferencesFromIntent, intent = " + intent);
}
requirePreferenceManager();
setPreferenceScreen(mPreferenceManager.inflateFromIntent(intent, getPreferenceScreen()));
}
setPreferenceScreen
/**
* Sets the root of the preference hierarchy that this activity is showing.
*
* @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
*
* @deprecated This function is not relevant for a modern fragment-based
* PreferenceActivity.
*/
@Deprecated
public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
requirePreferenceManager();
if (mPreferenceManager.setPreferences(preferenceScreen) && preferenceScreen != null) {
postBindPreferences();
CharSequence title = getPreferenceScreen().getTitle();
// Set the title of the activity
if (title != null) {
setTitle(title);
}
}
}
postBindPreferences
/**
* Posts a message to bind the preferences to the list view.
* <p>
* Binding late is preferred as any custom preference types created in
* {@link #onCreate(Bundle)} are able to have their views recycled.
*/
private void postBindPreferences() {
if (mHandler.hasMessages(MSG_BIND_PREFERENCES)) return;
mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
}
bindPreferences
private void bindPreferences() {
final PreferenceScreen preferenceScreen = getPreferenceScreen();
if (preferenceScreen != null) {
preferenceScreen.bind(getListView());
if (mSavedInstanceState != null) {
super.onRestoreInstanceState(mSavedInstanceState);
mSavedInstanceState = null;
}
}
PreferenceScreen.java
public void bind(ListView listView) {
listView.setOnItemClickListener(this);
listView.setAdapter(getRootAdapter());
onAttachedToActivity();
}
PreferenceGroup.java
@Override
protected void onAttachedToActivity() {
super.onAttachedToActivity();
// Mark as attached so if a preference is later added to this group, we
// can tell it we are already attached
mAttachedToActivity = true;
// Dispatch to all contained preferences
final int preferenceCount = getPreferenceCount();
for (int i = 0; i < preferenceCount; i++) {
getPreference(i).onAttachedToActivity();
}
}
Preference.java
protected void onAttachedToActivity() {
// At this point, the hierarchy that this preference is in is connected
// with all other preferences.
registerDependency();
}
registerDependency
private void registerDependency() {
if (TextUtils.isEmpty(mDependencyKey)) return;
Preference preference = findPreferenceInHierarchy(mDependencyKey);
if (preference != null) {
preference.registerDependent(this);
} else {
throw new IllegalStateException("Dependency \"" + mDependencyKey
+ "\" not found for preference \"" + mKey + "\" (title: \"" + mTitle + "\"");
}
registerDependent
private void registerDependent(Preference dependent) {
if (mDependents == null) {
mDependents = new ArrayList<Preference>();
}
mDependents.add(dependent);
dependent.onDependencyChanged(this, shouldDisableDependents());
}
其中 private List mDependents;
对list 设置显示参数通过HeaderAdapter 完成的。
private static class HeaderAdapter extends ArrayAdapter<Header> {
private static class HeaderViewHolder {
ImageView icon;
TextView title;
TextView summary;
}
private LayoutInflater mInflater;
private int mLayoutResId;
private boolean mRemoveIconIfEmpty;
public HeaderAdapter(Context context, List<Header> objects, int layoutResId,
boolean removeIconBehavior) {
super(context, 0, objects);
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mLayoutResId = layoutResId;
mRemoveIconIfEmpty = removeIconBehavior;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
HeaderViewHolder holder;
View view;
if (convertView == null) {
view = mInflater.inflate(mLayoutResId, parent, false);
holder = new HeaderViewHolder();
holder.icon = (ImageView) view.findViewById(com.android.internal.R.id.icon);
holder.title = (TextView) view.findViewById(com.android.internal.R.id.title);
holder.summary = (TextView) view.findViewById(com.android.internal.R.id.summary);
view.setTag(holder);
} else {
view = convertView;
holder = (HeaderViewHolder) view.getTag();
}
// All view fields must be updated every time, because the view may be recycled
Header header = getItem(position);
if (mRemoveIconIfEmpty) {
if (header.iconRes == 0) {
holder.icon.setVisibility(View.GONE);
} else {
holder.icon.setVisibility(View.VISIBLE);
holder.icon.setImageResource(header.iconRes);
}
} else {
holder.icon.setImageResource(header.iconRes);
}
holder.title.setText(header.getTitle(getContext().getResources()));
CharSequence summary = header.getSummary(getContext().getResources());
if (!TextUtils.isEmpty(summary)) {
holder.summary.setVisibility(View.VISIBLE);
holder.summary.setText(summary);
} else {
holder.summary.setVisibility(View.GONE);
}
return view;
}
}
在oncreate 中通过完成。
setListAdapter(new HeaderAdapter(this, mHeaders, mPreferenceHeaderItemResId,
mPreferenceHeaderRemoveEmptyIcon));