何时使用 sharedpreferencee Headers

Preference Headers不显示
使用Preference-Headers重写PreferenceActivity。但是按照步骤操作之后header没显示,白屏。
&?xml version="1.0" encoding="utf-8"?&
&preference-headers xmlns:android="/apk/res/android"&
&preference-headers xmlns:android="/apk/res/android"&
android:fragment="com.mikebdev.refuel.SettingsActivity$DesignFragment"
android:title="@string/pref_header_design"
android:summary="@string/pref_header_design_summary"
android:fragment="com.mikebdev.refuel.SettingsActivity$SettingsFragment"
android:title="@string/pref_header_units"
android:summary="@string/pref_header_units_summary"/&
android:fragment="com.mikebdev.refuel.SettingsActivity$DatabaseFragment"
android:title="@string/pref_header_db"
android:summary="@string/pref_header_db_summary"/&
&/preference-headers&
&/preference-headers&
SettingsActivity内容:
import android.app.AlertD
import android.content.C
import android.content.DialogI
import android.os.B
import android.os.E
import android.preference.P
import android.preference.PreferenceA
import android.preference.PreferenceF
import android.preference.PreferenceM
import android.widget.T
import com.google.analytics.tracking.android.EasyT
import java.io.F
import java.io.FileInputS
import java.io.FileNotFoundE
import java.io.FileOutputS
import java.io.IOE
import java.io.InputS
import java.io.OutputS
import java.util.L
public class SettingsActivity extends PreferenceActivity {
public static final String PREFS_NAME = "RFPref";
public static PreferenceManager prefM
public void onBuildHeaders(List&Header& target) {
loadHeadersFromResource(R.xml.pref_headers, target);
不知道哪里出问题?
按赞数排序
找到原因了,是冗杂的元素引起的,去掉里面的就好了。
android:fragment="com.mikebdev.refuel.SettingsActivity$DesignFragment"
android:fragment="com.mikebdev.refuel.SettingsActivity$SettingsFragment"
android:fragment="com.mikebdev.refuel.SettingsActivity$DatabaseFragment"
这几个fragment都写了吗?
其他相似问题
相关参考资料Related Venues
Conditional Preference Headers
Android 3.0 introduced the new, two-tier form of PreferenceActivity.
You supply header+fragment pairs. Android shows the user the list of
headers, and upon clicking on a header, Android shows the fragment.
However, on phone-sized devices, it will do those one a time: the list
of fragments fills the screen, and then the chosen fragment fills the
screen. On larger devices, PreferenceActivity shows them both
side by side. This is a classic rendition of
However, it does tend to steer developers in the direction of displaying
headers all of the time. For many apps, that is rather pointless,
because there are too few preferences to collect to warrant having more
than one header.
One alternative approach is to use the headers on larger devices,
but skip them on smaller devices. That way, the user does not have to
tap past a single-item ListFragment just to get to the actual
preferences to adjust.
This is a wee bit tricky to implement.
The basic plan is to have smarts in onBuildHeaders() to handle this.
onBuildHeaders() is the callback that Android invokes on our
PreferenceActivity to let us define the headers to use in the
master-detail pattern. If we want to have headers, we would supply
if we want to skip the headers, we would instead fall
back to the classic (and, admittedly, deprecated)
addPreferencesFromResource() method to load up some preference
There is an isMultiPane() method on PreferenceActivity, starting
with API Level 11, that will tell you if the activity will render
with two fragments (master+detail) or not. In principle, this would
be ideal to use. Unfortunately, it does not seem to be designed to
be called from onBuildHeaders(). Similarly, addPreferencesFromResource()
does not seem to be callable from onBuildHeaders(). Both are due
to timing: onBuildHeaders() is called in the middle of the
PreferenceActivity onCreate() processing.
So, we have to do some fancy footwork.
By examining ,
you will see that the logic that drives the single-pane vs. dual-pane
UI decision boils down to:
onIsHidingHeaders() || !onIsMultiPane()
If that expression returns true, we are in single- otherwise,
we are in dual-pane mode. onIsHidingHeaders() will normally return
false, while onIsMultiPane() will return either true or false
based upon screen size. Specifically, onIsMultiPane() looks at an
internal boolean resource (com.android.internal.R.bool.preferences_prefer_dual_pane),
which has different definitions based upon screen size. At present, it
will be true for -sw720dp devices, false otherwise.
So, we can leverage this information in a PreferenceActivity to
conditionally load our headers:
public class EditPreferences extends SherlockPreferenceActivity {
private boolean needResource=
@SuppressWarnings("deprecation")
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (needResource
|| Build.VERSION.SDK_INT & Build.VERSION_CODES.HONEYCOMB) {
addPreferencesFromResource(R.xml.preferences);
public void onBuildHeaders(List&Header& target) {
if (onIsHidingHeaders() || !onIsMultiPane()) {
needResource=
loadHeadersFromResource(R.xml.preference_headers, target);
Here, if we are in dual-pane mode, onBuildHeaders() populates the
headers as normal. If, though, we are in single-pane mode, we skip
that step and make note that we need to do some more work in onCreate().
Then, in onCreate(), if we did not load our headers, or if we are
on API Level 10 or below, we use the classic addPreferencesFromResource()
The net result is that on Android 3.0+ tablets, we get the dual-pane,
master-detail look with our one header, but on smaller devices
(regardless of version), we roll straight to the preferences themselves.下次自动登录
现在的位置:
& 综合 & 正文
初识android4.1.1 Settings 界面(以WIFI功能块为主线)
这段时间一直在看android,发现如果就这样漫无目的的看,真是很纠结,看的我都要睡着了。所有,就根据某一个功能模块去看,然后慢慢深入了。
(ps:第一次写博客有点惶恐啊)
首先是Settings运行界面,界面采用了Fragment界面。分为两个部分,左侧的为Settings各个系统设置,右侧则是显示左侧属性的详细信息和相关设置。
一、首先说一下Fragment知识
Fragment是在android3.0才有的。一个Fragment表示在Activity中的部分的用户界面。在一个Activity中可以含有构建多个Fragment界面。你可以将Fragment作为Activity中的一个模块,它有自己的生命周期,接受自己的输入事件,也可以在Activity运行时添加和删除它,有点像一个“sub Activity”,你可以在不同的Activity中重复使用。一般Fragment都嵌套在一个Activity中,这个Fragment的生命周期直接受主Activity的影响。详细见:/guide/components/fragments.html
二、加载Settings属性项(就是我们看到的header)
public void onBuildHeaders(List&Header& headers) {
loadHeadersFromResource(R.xml.settings_headers, headers);//从xml文件下settings_header.xml源码加载headers
updateHeaderList(headers);
以下是settings_header.xml
&?xml version="1.0" encoding="utf-8"?&
&preference-headers
xmlns:android="/apk/res/android"&
&!-- WIRELESS and NETWORKS --&
&header android:title="@string/header_category_wireless_networks" /&
&!-- Wifi --&
android:id="@+id/wifi_settings"
android:fragment="com.android.settings.wifi.WifiSettings"
android:title="@string/wifi_settings_title"
android:icon="@drawable/ic_settings_wireless" /&
&!-- Bluetooth --&
android:id="@+id/bluetooth_settings"
android:fragment="com.android.settings.bluetooth.BluetoothSettings"
android:title="@string/bluetooth_settings_title"
android:icon="@drawable/ic_settings_bluetooth2" /&
&!-- Data Usage --&
android:id="@+id/data_usage_settings"
android:fragment="com.android.settings.DataUsageSummary"
android:title="@string/data_usage_summary_title"
android:icon="@drawable/ic_settings_data_usage" /&
&!-- Operator hook --&
android:fragment="com.android.settings.WirelessSettings"
android:id="@+id/operator_settings"&
&intent android:action="com.android.settings.OPERATOR_APPLICATION_SETTING" /&
&!-- Other wireless and network controls --&
android:id="@+id/wireless_settings"
android:title="@string/radio_controls_title"
android:breadCrumbTitle="@string/wireless_networks_settings_title"
android:fragment="com.android.settings.WirelessSettings"
android:icon="@drawable/empty_icon" /&
&!-- DEVICE --&
&header android:title="@string/header_category_device" /&
&!-- Sound --&
android:id="@+id/sound_settings"
android:icon="@drawable/ic_settings_sound"
android:fragment="com.android.settings.SoundSettings"
android:title="@string/sound_settings" /&
&!-- Display --&
android:id="@+id/display_settings"
android:icon="@drawable/ic_settings_display"
android:fragment="com.android.settings.DisplaySettings"
android:title="@string/display_settings" /&
&!-- Hdmi --&
android:id="@+id/hdmi_settings"
android:icon="@drawable/ic_settings_hdmi"
android:fragment="com.android.settings.HdmiControllerActivity"
android:title="@string/hdmi_settings" /&
android:id="@+id/screenshot_settings"
android:icon="@drawable/capture"
android:fragment="com.android.settings.ScreenshotSetting"
android:title="@string/screenshot_manager"/&
&!-- Storage --&
android:id="@+id/storage_settings"
android:fragment="com.android.settings.deviceinfo.Memory"
android:icon="@drawable/ic_settings_storage"
android:title="@string/storage_settings" /&
&!-- Battery --&
android:id="@+id/battery_settings"
android:fragment="com.android.settings.fuelgauge.PowerUsageSummary"
android:icon="@drawable/ic_settings_battery"
android:title="@string/power_usage_summary_title" /&
&!-- Application Settings --&
android:fragment="com.android.settings.applications.ManageApplications"
android:icon="@drawable/ic_settings_applications"
android:title="@string/applications_settings"
android:id="@+id/application_settings" /&
&!-- Manufacturer hook --&
android:fragment="com.android.settings.WirelessSettings"
android:id="@+id/manufacturer_settings"&
&intent android:action="com.android.settings.MANUFACTURER_APPLICATION_SETTING" /&
&!-- PERSONAL --&
&header android:title="@string/header_category_personal" /&
&!-- Manage users --&
android:fragment="com.android.settings.users.UserSettings"
android:icon="@drawable/ic_settings_sync"
android:title="@string/user_settings_title"
android:id="@+id/user_settings" /&
&!-- Location --&
android:fragment="com.android.settings.LocationSettings"
android:icon="@drawable/ic_settings_location"
android:title="@string/location_settings_title"
android:id="@+id/location_settings" /&
&!-- Security --&
android:fragment="com.android.settings.SecuritySettings"
android:icon="@drawable/ic_settings_security"
android:title="@string/security_settings_title"
android:id="@+id/security_settings" /&
&!-- Language --&
android:id="@+id/language_settings"
android:fragment="com.android.settings.inputmethod.InputMethodAndLanguageSettings"
android:icon="@drawable/ic_settings_language"
android:title="@string/language_settings" /&
&!-- Backup and reset --&
android:fragment="com.android.settings.PrivacySettings"
android:icon="@drawable/ic_settings_backup"
android:title="@string/privacy_settings"
android:id="@+id/privacy_settings" /&
ACCOUNTS section --&
android:id="@+id/account_settings"
android:title="@string/account_settings" /&
android:id="@+id/account_add"
android:title="@string/add_account_label"
android:icon="@drawable/ic_menu_add"&
android:action="android.settings.ADD_ACCOUNT_SETTINGS"/&
&!-- SYSTEM --&
&header android:title="@string/header_category_system" /&
&!-- Dock --&
android:id="@+id/dock_settings"
android:fragment="com.android.settings.DockSettings"
android:icon="@drawable/ic_settings_dock"
android:title="@string/dock_settings" /&
&!-- Date & Time --&
android:id="@+id/date_time_settings"
android:fragment="com.android.settings.DateTimeSettings"
android:icon="@drawable/ic_settings_date_time"
android:title="@string/date_and_time_settings_title" /&
&!-- Accessibility feedback --&
android:id="@+id/accessibility_settings"
android:fragment="com.android.settings.AccessibilitySettings"
android:icon="@drawable/ic_settings_accessibility"
android:title="@string/accessibility_settings" /&
&!-- Development --&
android:id="@+id/development_settings"
android:fragment="com.android.settings.DevelopmentSettings"
android:icon="@drawable/ic_settings_development"
android:title="@string/development_settings_title" /&
&!-- About Device --&
android:id="@+id/about_settings"
android:fragment="com.android.settings.DeviceInfoSettings"
android:icon="@drawable/ic_settings_about"
android:title="@string/about_settings" /&
&/preference-headers&
可以注意到每个header属性都有android:fragment值,这就是使得每个header对于到fragment左侧的详细信息。
我们可以看下WifiSetting这个类
* Two types of UI are provided here.
* The first is for "usual Settings", appearing as any other Setup fragment.
* The second is for Setup Wizard, with a simplified interface that hides the action bar
* and menus.
public class WifiSettings extends SettingsPreferenceFragment
implements DialogInterface.OnClickListener
//重写onActivityCreated方法
public void onActivityCreated(Bundle savedInstanceState) {
addPreferencesFromResource(R.xml.wifi_settings);
R.xml.wifi_settins就是右侧的布局了
三、左侧嵌套的控件
那个打开和关闭的按钮,开始以为是checkBox,后面才知道是Switch(oh,my good!着实小白了,果断查文档恶补下)
从文档得知Switch其实跟checkBox差不多,也是继承自CompoundButton类。
private static class HeaderAdapter extends ArrayAdapter&Header& {
public View getView(int position, View convertView, ViewGroup parent) {
case HEADER_TYPE_SWITCH:
view = mInflater.inflate(R.layout.preference_header_switch_item, parent,
false);//加载preference_header_switch_item
holder.icon = (ImageView) view.findViewById(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);
holder.switch_ = (Switch) view.findViewById(R.id.switchWidget);
查看preference_header_switch_item布局
&?xml version="1.0" encoding="utf-8"?&
&!-- Layout of a header item in PreferenceActivity. --&
&LinearLayout xmlns:android="/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:background="?android:attr/activatedBackgroundIndicator"
android:gravity="center_vertical"
android:paddingRight="?android:attr/scrollbarSize"&
&LinearLayout
android:layout_width="@dimen/header_icon_width"
android:layout_marginLeft="6dip"
android:layout_marginRight="6dip"
android:layout_height="wrap_content"&
&ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" /&
&/LinearLayout&
&RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="2dip"
android:layout_marginRight="6dip"
android:layout_marginTop="6dip"
android:layout_marginBottom="6dip"
android:layout_weight="1"&
&TextView android:id="@+android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:ellipsize="marquee"
android:fadingEdge="horizontal" /&
&TextView android:id="@+android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@android:id/title"
android:layout_alignLeft="@android:id/title"
android:textAppearance="?android:attr/textAppearanceSmall"
android:ellipsize="end"
android:maxLines="2" /&
&/RelativeLayout&
&Switch android:id="@+id/switchWidget"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="8dip"
android:focusable="false"
android:clickable="true" /&
&/LinearLayout&
可以看到Switch标签,这个就是那个on/off了
&&&&推荐文章:
【上篇】【下篇】转载请注明出处:http://blog.csdn.net/droyon/article/details/
本文讲述PreferenceActivity中单击事件的处理,重点记述mCurrentHeader以及设置源代码Settings中的mLastHeader、mCurrentHeader、mParentHeader的作用。主要以多屏幕为例。
在PreferenceActivity中,当我们点击Header时,其处理流程分为&& 单屏幕和双屏幕两套流程。
1、单屏幕(SinglePane)
&1.1、点击每一项,执行如下代码.
public void onHeaderClick(Header header, int position) {
Log.d(LOG_TAG, &Settings onHeaderClick Header is:&+header.title+&,position is:&+position+&,mLastHeader is:&+mLastHeader);
boolean revert =
if (header.id == R.id.account_add) {
Log.d(LOG_TAG, &Settings onHeaderClick Header id is:&+header.id+&, R.id.account_add is:&+R.id.account_add+&,revert is:&+revert);
super.onHeaderClick(header, position);
if (revert && mLastHeader != null) {
highlightHeader((int) mLastHeader.id);
mLastHeader =
关于hightlightHeader下面有详细介绍,这里就不介绍了。
主要执行父类的onHeaderClick方法。
public void onHeaderClick(Header header, int position) {
if (header.fragment != null) {
if (mSinglePane) {
int titleRes = header.breadCrumbTitleR
int shortTitleRes = header.breadCrumbShortTitleR
if (titleRes == 0) {
titleRes = header.titleR
shortTitleRes = 0;
startWithFragment(header.fragment, header.fragmentArguments, null, 0,
titleRes, shortTitleRes);
switchToHeader(header);
} else if (header.intent != null) {
startActivity(header.intent);
因为mSinglePane为true,故执行startWithFragment。
Intent intent = onBuildStartFragmentIntent(fragmentName, args, titleRes, shortTitleRes);
if (resultTo == null) {
startActivity(intent);
resultTo.startActivityForResult(intent, resultRequestCode);
我们看到这里会执行onBuildStartFragmentIntent。
public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,
int titleRes, int shortTitleRes) {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setClass(this, getClass());
intent.putExtra(EXTRA_SHOW_FRAGMENT, fragmentName);
intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
intent.putExtra(EXTRA_SHOW_FRAGMENT_TITLE, titleRes);
intent.putExtra(EXTRA_SHOW_FRAGMENT_SHORT_TITLE, shortTitleRes);
intent.putExtra(EXTRA_NO_HEADERS, true);
这个方法在子类中有重写。
Settings.java
public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,
int titleRes, int shortTitleRes) {
Intent intent = super.onBuildStartFragmentIntent(fragmentName, args,
titleRes, shortTitleRes);
// some fragments want to avoid split actionbar
if (DataUsageSummary.class.getName().equals(fragmentName) ||
PowerUsageSummary.class.getName().equals(fragmentName) ||
AccountSyncSettings.class.getName().equals(fragmentName) ||
UserDictionarySettings.class.getName().equals(fragmentName)) {
intent.putExtra(EXTRA_CLEAR_UI_OPTIONS, true);
intent.setClass(this, SubSettings.class);
这里主要是为intent增加了SubSettings.class,因为Header中的fragment,需要有个Activity依附。
ps://******log信息
01-08 21:55:05.857: D/Hlwang_Settings(25569): Settings onBuildStartFragmentIntent fragmentName is:com.android.settings.wifi.WifiSettings
//*************************
1.5、由1.3可知,这个intent会被startActivity(intent)发送出去。
Intent会被SubSettings接收,由于SubSettings继承自Settigns.java,因此,这个Intent还会被Settings.java执行。
public class SubSettings extends Settings {
1.6、在Settings.java的onCreate中:
在onCreate中会执行getMeteData以及getIntent。这两个方法共同作用得到了mFragmentClass。然后执行super.onCreate
private void getMetaData() {
ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
PackageManager.GET_META_DATA);
if (ai == null || ai.metaData == null)
mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);
mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
// Check if it has a parent specified and create a Header object
final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);
String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
if (parentFragmentClass != null) {
mParentHeader = new Header();
mParentHeader.fragment = parentFragmentC
if (parentHeaderTitleRes != 0) {
mParentHeader.title = getResources().getString(parentHeaderTitleRes);
} catch (NameNotFoundException nnfe) {
// No recovery
}public Intent getIntent() {
Intent superIntent = super.getIntent();
String startingFragment = getStartingFragmentClass(superIntent);
// This is called from super.onCreate, isMultiPane() is not yet reliable
// Do not use onIsHidingHeaders either, which relies itself on this method
if (startingFragment != null && !onIsMultiPane()) {
Intent modIntent = new Intent(superIntent);
modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);
Bundle args = superIntent.getExtras();
if (args != null) {
args = new Bundle(args);
args = new Bundle();
args.putParcelable(&intent&, superIntent);
modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, superIntent.getExtras());
return modI
return superI
ps://****log信息
01-08 21:55:05.897: D/Hlwang_Settings(25569): Settings getStartingFragmentClass intentClass is:com.android.settings.SubSettingsgetClassName is:com.android.settings.SubSettings
//***********
PreferenceActivity.java
String initialFragment = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT);
Bundle initialArguments = getIntent().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
int initialTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_TITLE, 0);
int initialShortTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_SHORT_TITLE, 0);
这样initialFragment得到了初始化,并且。
if (initialFragment != null && mSinglePane) {
// If we are just showing a fragment, we want to run in
// new fragment mode, but don't need to compute and show
// the headers.
switchToHeader(initialFragment, initialArguments);
if (initialTitle != 0) {
CharSequence initialTitleStr = getText(initialTitle);
CharSequence initialShortTitleStr = initialShortTitle != 0
? getText(initialShortTitle) :
showBreadCrumbs(initialTitleStr, initialShortTitleStr);
这里跳用switchToHeader将Fragment切换到右边窗体中。
if (initialFragment != null && mSinglePane) {
// Single pane, showing just a prefs fragment.
findViewById(com.android.internal.R.id.headers).setVisibility(View.GONE);
mPrefsContainer.setVisibility(View.VISIBLE);
if (initialTitle != 0) {
CharSequence initialTitleStr = getText(initialTitle);
CharSequence initialShortTitleStr = initialShortTitle != 0
? getText(initialShortTitle) :
showBreadCrumbs(initialTitleStr, initialShortTitleStr);
这里,将左边窗体的Header 列表隐藏。
2、双屏幕(平板)
2.1、首先执行单击事件
public void onHeaderClick(Header header, int position) {
if (header.fragment != null) {
if (mSinglePane) {
int titleRes = header.breadCrumbTitleR
int shortTitleRes = header.breadCrumbShortTitleR
if (titleRes == 0) {
titleRes = header.titleR
shortTitleRes = 0;
startWithFragment(header.fragment, header.fragmentArguments, null, 0,
titleRes, shortTitleRes);
switchToHeader(header);
} else if (header.intent != null) {
startActivity(header.intent);
我们在这个方法内看到,首先判断fragment以及intent,然后会根据mSinglePane来判断进入那个逻辑里。mSinglePane是单屏幕或者双屏幕,此处为false。
在双屏幕中,此处会执行switchToHeader(header)方法。
if (mCurHeader == header) {
// This is the header we are currently displaying.
Just make sure
// to pop the stack up to its root state.
getFragmentManager().popBackStack(BACK_STACK_PREFS,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
int direction = mHeaders.indexOf(header) - mHeaders.indexOf(mCurHeader);
switchToHeaderInner(header.fragment, header.fragmentArguments, direction);
setSelectedHeader(header);
这里首先会判断mCurrentHeader是否为要切换的header。如果mCurrentHeader == header,那么执行:
getFragmentManager().popBackStack(BACK_STACK_PREFS,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
int direction = mHeaders.indexOf(header) - mHeaders.indexOf(mCurHeader);
switchToHeaderInner(header.fragment, header.fragmentArguments, direction);
setSelectedHeader(header);
在这里,direction没有发挥作用。这里应该是判断ListView是向上滚动还是向下滚动。
我们看switchToHeaderInnr方法。
getFragmentManager().popBackStack(BACK_STACK_PREFS,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
Fragment f = Fragment.instantiate(this, fragmentName, args);
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
transaction.replace(com.android.internal.R.id.prefs, f);
mitAllowingStateLoss();
这个方法处理fragment的切换。例如:我们在左边,点击了Bluetooth的设置项,那么其fragment会在右边显示。
2.4,最后执行setSelectedHeader方法。
void setSelectedHeader(Header header) {
mCurHeader =
int index = mHeaders.indexOf(header);
if (index &= 0) {
getListView().setItemChecked(index, true);
getListView().clearChoices();
showBreadCrumbs(header);
在这个方法中主要处理ListView的setItemChecked状态。如上图中蓝牙设置项的选中底色。并且设置Breadcrumb(标题)
void showBreadCrumbs(Header header) {
if (header != null) {
CharSequence title = header.getBreadCrumbTitle(getResources());
if (title == null) title = header.getTitle(getResources());
if (title == null) title = getTitle();
showBreadCrumbs(title, header.getBreadCrumbShortTitle(getResources()));
showBreadCrumbs(getTitle(), null);
if (mFragmentBreadCrumbs == null) {
View crumbs = findViewById(android.R.id.title);
// For screens with a different kind of title, don't create breadcrumbs.
mFragmentBreadCrumbs = (FragmentBreadCrumbs)
} catch (ClassCastException e) {
if (mFragmentBreadCrumbs == null) {
if (title != null) {
setTitle(title);
mFragmentBreadCrumbs.setMaxVisible(2);
mFragmentBreadCrumbs.setActivity(this);
mFragmentBreadCrumbs.setTitle(title, shortTitle);
mFragmentBreadCrumbs.setParentTitle(null, null, null);
&//*****************************************************************************************
2.6、在设置应用的源代码中,Settings.java类中。上述的处理存在如下差别。
Settings.java重新了switchHeader方法:
public void switchToHeader(Header header) {
if (!mInLocalHeaderSwitch) {
mCurrentHeader =
mParentHeader =
super.switchToHeader(header);
mInLocalHeaderSwitch在我们点击条目的时候为false,故,Settings.java中定义的mCurrentHeader以及mParentHeader会赋值null。然后执行super.switchToHeader()。
&二、外部通过Action进入设置应用的流程。(多屏幕的状态下)
Intent intent=new Intent();
intent.setClassName(this, &c&);
intent.setAction(&android.intent.action.PICK_ACTIVITY&);
intent.setAction(&android.settings.WIFI_IP_SETTINGS&);
startActivity(intent);
通过上述代码,会进入如下界面。
启动这个界面会经历如下流程,
首先Settigns.java的onCreate方法。
protected void onCreate(Bundle savedInstanceState) {
if (getIntent().getBooleanExtra(EXTRA_CLEAR_UI_OPTIONS, false)) {
getWindow().setUiOptions(0);
getMetaData();
mInLocalHeaderSwitch =
super.onCreate(savedInstanceState);
mInLocalHeaderSwitch =
if (!onIsHidingHeaders() && onIsMultiPane()) {
highlightHeader();
// Force the title so that it doesn't get overridden by a direct launch of
// a specific settings screen.
setTitle(R.string.settings_label);
// Retrieve any saved state
if (savedInstanceState != null) {
mCurrentHeader = savedInstanceState.getParcelable(SAVE_KEY_CURRENT_HEADER);
mParentHeader = savedInstanceState.getParcelable(SAVE_KEY_PARENT_HEADER);
// If the current header was saved, switch to it
if (savedInstanceState != null && mCurrentHeader != null) {
//switchToHeaderLocal(mCurrentHeader);
showBreadCrumbs(mCurrentHeader.title, null);
if (mParentHeader != null) {
setParentTitle(mParentHeader.title, null, new OnClickListener() {
public void onClick(View v) {
switchToParent(mParentHeader.fragment);
// TODO Add support for android.R.id.home in all Setting's onOptionsItemSelected
// getActionBar().setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP,
// ActionBar.DISPLAY_HOME_AS_UP);
在这个方法内,首先执行getIntent方法,Settings重新了这个方法。
public Intent getIntent() {
Intent superIntent = super.getIntent();
String startingFragment = getStartingFragmentClass(superIntent);
// This is called from super.onCreate, isMultiPane() is not yet reliable
// Do not use onIsHidingHeaders either, which relies itself on this method
if (startingFragment != null && !onIsMultiPane()) {
Intent modIntent = new Intent(superIntent);
modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);
Bundle args = superIntent.getExtras();
if (args != null) {
args = new Bundle(args);
args = new Bundle();
args.putParcelable(&intent&, superIntent);
modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, superIntent.getExtras());
return modI
return superI
在这个方法内,会调用getStartingFragmentClass方法。
protected String getStartingFragmentClass(Intent intent) {
if (mFragmentClass != null) return mFragmentC
String intentClass = intent.getComponent().getClassName();
if (intentClass.equals(getClass().getName()))
if (&com.android.settings.ManageApplications&.equals(intentClass)
|| &com.android.settings.RunningServices&.equals(intentClass)
|| &com.android.settings.applications.StorageUse&.equals(intentClass)) {
// Old names of manage apps.
intentClass = com.android.settings.applications.ManageApplications.class.getName();
return intentC
这个方法中,intentClass为:com.android.settings.Settings$AdvancedWifiSettingsActivity
ps://****************************************************************log信息
01-08 21:10:06.737: D/Hlwang_Settings(15602): Settings getStartingFragmentClass mFragmentClass is:null
01-08 21:10:06.737: D/Hlwang_Settings(15602): Settings getStartingFragmentClass intentClass is:com.android.settings.Settings$AdvancedWifiSettingsActivity
//************************************************
3、我们继续看onCreate方法。在往下会执行getMeteData方法。
private void getMetaData() {
ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
PackageManager.GET_META_DATA);
if (ai == null || ai.metaData == null)
mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);
mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
// Check if it has a parent specified and create a Header object
final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);
String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
if (parentFragmentClass != null) {
mParentHeader = new Header();
mParentHeader.fragment = parentFragmentC
if (parentHeaderTitleRes != 0) {
mParentHeader.title = getResources().getString(parentHeaderTitleRes);
} catch (NameNotFoundException nnfe) {
// No recovery
这里,AdvancedWifiSettingsActivity在AndroidManifest.xml中的配置:
&activity android:name=&Settings$AdvancedWifiSettingsActivity&
android:label=&@string/wifi_advanced_settings_label&
android:configChanges=&orientation|keyboardHidden|screenSize&
android:clearTaskOnLaunch=&true&&
&intent-filter&
&action android:name=&android.intent.action.MAIN& /&
&action android:name=&android.settings.WIFI_IP_SETTINGS& /&
&category android:name=&android.intent.category.VOICE_LAUNCH& /&
&category android:name=&android.intent.category.DEFAULT& /&
&/intent-filter&
&meta-data android:name=&com.android.settings.FRAGMENT_CLASS&
android:value=&com.android.settings.wifi.AdvancedWifiSettings& /&
&meta-data android:name=&com.android.settings.TOP_LEVEL_HEADER_ID&
android:resource=&@id/wifi_settings& /&
&meta-data android:name=&com.android.settings.PARENT_FRAGMENT_TITLE&
android:resource=&@string/wifi_settings& /&
&meta-data android:name=&com.android.settings.PARENT_FRAGMENT_CLASS&
android:value=&com.android.settings.Settings$WifiSettingsActivity& /&
&/activity&
故而:mTopLevelId = @+id/wifi_settigns,mFragmentClass为:com.android.settings.wifi.AdvancedWifiSettings,mParentClass为:com.android.settings.Settings$WifiSettingsActivity
ps://************************log信息
01-08 21:10:06.747: D/Hlwang_Settings(15602): Settings getMetaData
01-08 21:10:06.747: D/Hlwang_Settings(15602): Settings getMetaData mFragmentClass is:com.android.settings.wifi.AdvancedWifiSettings
01-08 21:10:06.747: D/Hlwang_Settings(15602): Settings getMetaData parentFragmentClass is:com.android.settings.Settings$WifiSettingsActivity
//******************************
4、继续onCreate执行,接下来会执行:
mInLocalHeaderSwitch =
super.onCreate(savedInstanceState);
mInLocalHeaderSwitch =
这里会执行super.onCreate方法。之所以用mInLocalHeaderSwitch包裹,主要是因为super.onCreate方法,会执行到PreferenceActitivity.java中的 :
if (!mSinglePane) {
if (initialFragment == null) {
Header h = onGetInitialHeader();
switchToHeader(h);
switchToHeader(initialFragment, initialArguments);
Settings.java重写了switchToHeader方法。
public void switchToHeader(Header header) {
if (!mInLocalHeaderSwitch) {
mCurrentHeader =
mParentHeader =
super.switchToHeader(header);
这样mInLocalHeaderSwitch为true,不会清楚mCurrentHeader以及mParentHeader。
最后会执行super.switchToHeader方法,这个方法的执行,会将AdvancedWifiSettings加载到如上图所示的右边的区域内。
Settings.java还重新了onGetInitialHeader方法,这个方法为Header赋了正确的值。
public Header onGetInitialHeader() {
String fragmentClass = getStartingFragmentClass(super.getIntent());
if (fragmentClass != null) {
Header header = new Header();
header.fragment = fragmentC
header.title = getTitle();
header.fragmentArguments = getIntent().getExtras();
mCurrentHeader =
return mFirstH
5、最后一步,给上图左边的部分加上setItemChecked效果。也即是上图中的选中状态底纹。
if (!onIsHidingHeaders() && onIsMultiPane()) {
highlightHeader();
// Force the title so that it doesn't get overridden by a direct launch of
// a specific settings screen.
setTitle(R.string.settings_label);
}private void highlightHeader() {
if (mTopLevelHeaderId != 0) {
Integer index = mHeaderIndexMap.get(mTopLevelHeaderId);
if (index != null) {
getListView().setItemChecked(index, true);
getListView().smoothScrollToPosition(index);
mTopLevelHeaderId,我们在getMeteData方法中得到。
一、在多屏幕中,mFirstHeader的作用主要是为了正确的切换第一个Header。
mFirstHeader的初始化
if (mFirstHeader == null &&
HeaderAdapter.getHeaderType(header) != HeaderAdapter.HEADER_TYPE_CATEGORY) {
mFirstHeader =
如果为空,那么mFirstHeader为最靠前的第一个category。
mFirstHeader的使用:
public Header onGetInitialHeader() {
String fragmentClass = getStartingFragmentClass(super.getIntent());
if (fragmentClass != null) {
Header header = new Header();
header.fragment = fragmentC
header.title = getTitle();
header.fragmentArguments = getIntent().getExtras();
mCurrentHeader =
return mFirstH
如果getStarttingFragmentClass为null,那么返回mFirstHeader。
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
// If it is not launched from history, then reset to top-level
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0
&& mFirstHeader != null && !onIsHidingHeaders() && onIsMultiPane()) {
switchToHeaderLocal(mFirstHeader);
&二、mCurrentHeader的作用,显示当前Header的title。
public Header onGetInitialHeader() {
String fragmentClass = getStartingFragmentClass(super.getIntent());
if (fragmentClass != null) {
Header header = new Header();
header.fragment = fragmentC
header.title = getTitle();
header.fragmentArguments = getIntent().getExtras();
mCurrentHeader =
return mFirstH
外部跳转得到了fragmentClass,那么会初始化mCurrentHeader。
另外的一处初始化:
private void switchToParent(String className) {
final ComponentName cn = new ComponentName(this, className);
final PackageManager pm = getPackageManager();
final ActivityInfo parentInfo = pm.getActivityInfo(cn, PackageManager.GET_META_DATA);
if (parentInfo != null && parentInfo.metaData != null) {
String fragmentClass = parentInfo.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
CharSequence fragmentTitle = parentInfo.loadLabel(pm);
Header parentHeader = new Header();
parentHeader.fragment = fragmentC
parentHeader.title = fragmentT
mCurrentHeader = parentH
switchToHeaderLocal(parentHeader);
highlightHeader();
mParentHeader = new Header();
mParentHeader.fragment
= parentInfo.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
mParentHeader.title = parentInfo.metaData.getString(META_DATA_KEY_PARENT_TITLE);
} catch (NameNotFoundException nnfe) {
Log.w(LOG_TAG, &Could not find parent activity : & + className);
在onCreate中。
if (savedInstanceState != null) {
mCurrentHeader = savedInstanceState.getParcelable(SAVE_KEY_CURRENT_HEADER);
mParentHeader = savedInstanceState.getParcelable(SAVE_KEY_PARENT_HEADER);
// If the current header was saved, switch to it
if (savedInstanceState != null && mCurrentHeader != null) {
//switchToHeaderLocal(mCurrentHeader);
showBreadCrumbs(mCurrentHeader.title, null);
三、mParentHeader,
private void getMetaData() {
ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
PackageManager.GET_META_DATA);
if (ai == null || ai.metaData == null)
mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);
mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
// Check if it has a parent specified and create a Header object
final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);
String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
if (parentFragmentClass != null) {
mParentHeader = new Header();
mParentHeader.fragment = parentFragmentC
if (parentHeaderTitleRes != 0) {
mParentHeader.title = getResources().getString(parentHeaderTitleRes);
} catch (NameNotFoundException nnfe) {
// No recovery
使用如上面的mCurrentHeader。
&此文从网络中自动搜索生成,不代表本网站赞成被搜索网站的内容或立场
&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&
软件世界网- &2014 蜀ICP备号 三峰网旗下网站

我要回帖

更多关于 preferenceloader 的文章

 

随机推荐