Android PreferenceActivity点击Header是如何处理的?

来源:互联网 发布:传奇挂机软件 编辑:程序博客网 时间:2024/04/30 08:02

本文转自点击打开链接


本文讲述PreferenceActivity中单击事件的处理,重点记述mCurrentHeader以及设置源代码Settings中的mLastHeader、mCurrentHeader、mParentHeader的作用。主要以多屏幕为例。

 

在PreferenceActivity中,当我们点击Header时,其处理流程分为   单屏幕和双屏幕两套流程。

1、单屏幕(SinglePane)

 1.1、点击每一项,执行如下代码.

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public void onHeaderClick(Header header, int position) {  
  2.         Log.d(LOG_TAG, "Settings onHeaderClick Header is:"+header.title+",position is:"+position+",mLastHeader is:"+mLastHeader);  
  3.           
  4.         boolean revert = false;  
  5.         if (header.id == R.id.account_add) {  
  6.             revert = true;  
  7.         }  
  8.         Log.d(LOG_TAG, "Settings onHeaderClick Header id is:"+header.id+", R.id.account_add is:"+R.id.account_add+",revert is:"+revert);  
  9.         super.onHeaderClick(header, position);  
  10.   
  11.         if (revert && mLastHeader != null) {  
  12.             highlightHeader((int) mLastHeader.id);  
  13.         } else {  
  14.             mLastHeader = header;  
  15.         }  
  16.     }  

关于hightlightHeader下面有详细介绍,这里就不介绍了。

主要执行父类的onHeaderClick方法。

1.2、

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public void onHeaderClick(Header header, int position) {  
  2.         if (header.fragment != null) {  
  3.             if (mSinglePane) {  
  4.                 int titleRes = header.breadCrumbTitleRes;  
  5.                 int shortTitleRes = header.breadCrumbShortTitleRes;  
  6.                 if (titleRes == 0) {  
  7.                     titleRes = header.titleRes;  
  8.                     shortTitleRes = 0;  
  9.                 }  
  10.                 startWithFragment(header.fragment, header.fragmentArguments, null0,  
  11.                         titleRes, shortTitleRes);  
  12.             } else {  
  13.                 switchToHeader(header);  
  14.             }  
  15.         } else if (header.intent != null) {  
  16.             startActivity(header.intent);  
  17.         }  
  18.     }  

因为mSinglePane为true,故执行startWithFragment。

1.3、

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. Intent intent = onBuildStartFragmentIntent(fragmentName, args, titleRes, shortTitleRes);  
  2.         if (resultTo == null) {  
  3.             startActivity(intent);  
  4.         } else {  
  5.             resultTo.startActivityForResult(intent, resultRequestCode);  
  6.         }  

我们看到这里会执行onBuildStartFragmentIntent。
1.4、

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,  
  2.             int titleRes, int shortTitleRes) {  
  3.         Intent intent = new Intent(Intent.ACTION_MAIN);  
  4.         intent.setClass(this, getClass());  
  5.         intent.putExtra(EXTRA_SHOW_FRAGMENT, fragmentName);  
  6.         intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);  
  7.         intent.putExtra(EXTRA_SHOW_FRAGMENT_TITLE, titleRes);  
  8.         intent.putExtra(EXTRA_SHOW_FRAGMENT_SHORT_TITLE, shortTitleRes);  
  9.         intent.putExtra(EXTRA_NO_HEADERS, true);  
  10.         return intent;  
  11.     }  

这个方法在子类中有重写。

Settings.java

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,  
  2.             int titleRes, int shortTitleRes) {  
  3.         Intent intent = super.onBuildStartFragmentIntent(fragmentName, args,  
  4.                 titleRes, shortTitleRes);  
  5.   
  6.         // some fragments want to avoid split actionbar  
  7.         if (DataUsageSummary.class.getName().equals(fragmentName) ||  
  8.                 PowerUsageSummary.class.getName().equals(fragmentName) ||  
  9.                 AccountSyncSettings.class.getName().equals(fragmentName) ||  
  10.                 UserDictionarySettings.class.getName().equals(fragmentName)) {  
  11.             intent.putExtra(EXTRA_CLEAR_UI_OPTIONS, true);  
  12.         }  
  13.   
  14.         intent.setClass(this, SubSettings.class);  
  15.         return intent;  
  16.     }  

这里主要是为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执行。

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class SubSettings extends Settings {  
  2. }  

1.6、在Settings.java的onCreate中:

在onCreate中会执行getMeteData以及getIntent。这两个方法共同作用得到了mFragmentClass。然后执行super.onCreate

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private void getMetaData() {  
  2.         try {  
  3.             ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),  
  4.                     PackageManager.GET_META_DATA);  
  5.             if (ai == null || ai.metaData == nullreturn;  
  6.             mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);  
  7.             mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);  
  8.               
  9.             // Check if it has a parent specified and create a Header object  
  10.             final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);  
  11.             String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);  
  12.             if (parentFragmentClass != null) {  
  13.                 mParentHeader = new Header();  
  14.                 mParentHeader.fragment = parentFragmentClass;  
  15.                 if (parentHeaderTitleRes != 0) {  
  16.                     mParentHeader.title = getResources().getString(parentHeaderTitleRes);  
  17.                 }  
  18.             }  
  19.         } catch (NameNotFoundException nnfe) {  
  20.             // No recovery  
  21.         }  
  22.     }  
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public Intent getIntent() {  
  2.         Intent superIntent = super.getIntent();  
  3.         String startingFragment = getStartingFragmentClass(superIntent);  
  4.         // This is called from super.onCreate, isMultiPane() is not yet reliable  
  5.         // Do not use onIsHidingHeaders either, which relies itself on this method  
  6.         if (startingFragment != null && !onIsMultiPane()) {  
  7.             Intent modIntent = new Intent(superIntent);  
  8.             modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);  
  9.             Bundle args = superIntent.getExtras();  
  10.             if (args != null) {  
  11.                 args = new Bundle(args);  
  12.             } else {  
  13.                 args = new Bundle();  
  14.             }  
  15.             args.putParcelable("intent", superIntent);  
  16.             modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, superIntent.getExtras());  
  17.             return modIntent;  
  18.         }  
  19.         return superIntent;  
  20.     }  

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

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. String initialFragment = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT);  
  2.         Bundle initialArguments = getIntent().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);  
  3.         int initialTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_TITLE, 0);  
  4.         int initialShortTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_SHORT_TITLE, 0);  


这样initialFragment得到了初始化,并且。

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. if (initialFragment != null && mSinglePane) {  
  2.                 // If we are just showing a fragment, we want to run in  
  3.                 // new fragment mode, but don't need to compute and show  
  4.                 // the headers.  
  5.                 switchToHeader(initialFragment, initialArguments);  
  6.                 if (initialTitle != 0) {  
  7.                     CharSequence initialTitleStr = getText(initialTitle);  
  8.                     CharSequence initialShortTitleStr = initialShortTitle != 0  
  9.                             ? getText(initialShortTitle) : null;  
  10.                     showBreadCrumbs(initialTitleStr, initialShortTitleStr);  
  11.                 }  
  12.   
  13.             }   

这里跳用switchToHeader将Fragment切换到右边窗体中。

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. if (initialFragment != null && mSinglePane) {  
  2.             // Single pane, showing just a prefs fragment.  
  3.             findViewById(com.android.internal.R.id.headers).setVisibility(View.GONE);  
  4.             mPrefsContainer.setVisibility(View.VISIBLE);  
  5.             if (initialTitle != 0) {  
  6.                 CharSequence initialTitleStr = getText(initialTitle);  
  7.                 CharSequence initialShortTitleStr = initialShortTitle != 0  
  8.                         ? getText(initialShortTitle) : null;  
  9.                 showBreadCrumbs(initialTitleStr, initialShortTitleStr);  
  10.             }  
  11.         }   


这里,将左边窗体的Header 列表隐藏。

 

 

2、双屏幕(平板)

2.1、首先执行单击事件

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public void onHeaderClick(Header header, int position) {  
  2.         if (header.fragment != null) {  
  3.             if (mSinglePane) {  
  4.                 int titleRes = header.breadCrumbTitleRes;  
  5.                 int shortTitleRes = header.breadCrumbShortTitleRes;  
  6.                 if (titleRes == 0) {  
  7.                     titleRes = header.titleRes;  
  8.                     shortTitleRes = 0;  
  9.                 }  
  10.                 startWithFragment(header.fragment, header.fragmentArguments, null0,  
  11.                         titleRes, shortTitleRes);  
  12.             } else {  
  13.                 switchToHeader(header);  
  14.             }  
  15.         } else if (header.intent != null) {  
  16.             startActivity(header.intent);  
  17.         }  
  18.     }  


我们在这个方法内看到,首先判断fragment以及intent,然后会根据mSinglePane来判断进入那个逻辑里。mSinglePane是单屏幕或者双屏幕,此处为false。

在双屏幕中,此处会执行switchToHeader(header)方法。

2.2、

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. if (mCurHeader == header) {  
  2.             // This is the header we are currently displaying.  Just make sure  
  3.             // to pop the stack up to its root state.  
  4.             getFragmentManager().popBackStack(BACK_STACK_PREFS,  
  5.                     FragmentManager.POP_BACK_STACK_INCLUSIVE);  
  6.         } else {  
  7.             int direction = mHeaders.indexOf(header) - mHeaders.indexOf(mCurHeader);  
  8.             switchToHeaderInner(header.fragment, header.fragmentArguments, direction);  
  9.             setSelectedHeader(header);  
  10.         }  

这里首先会判断mCurrentHeader是否为要切换的header。如果mCurrentHeader == header,那么执行:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. getFragmentManager().popBackStack(BACK_STACK_PREFS,  
  2.                     FragmentManager.POP_BACK_STACK_INCLUSIVE);  


否则:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. int direction = mHeaders.indexOf(header) - mHeaders.indexOf(mCurHeader);  
  2.             switchToHeaderInner(header.fragment, header.fragmentArguments, direction);  
  3.             setSelectedHeader(header);  

在这里,direction没有发挥作用。这里应该是判断ListView是向上滚动还是向下滚动。

我们看switchToHeaderInnr方法。

2.3、

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. getFragmentManager().popBackStack(BACK_STACK_PREFS,  
  2.                 FragmentManager.POP_BACK_STACK_INCLUSIVE);  
  3.         Fragment f = Fragment.instantiate(this, fragmentName, args);  
  4.         FragmentTransaction transaction = getFragmentManager().beginTransaction();  
  5.         transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);  
  6.         transaction.replace(com.android.internal.R.id.prefs, f);  
  7.         transaction.commitAllowingStateLoss();  

这个方法处理fragment的切换。例如:我们在左边,点击了Bluetooth的设置项,那么其fragment会在右边显示。

 

2.4,最后执行setSelectedHeader方法。

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. void setSelectedHeader(Header header) {  
  2.         mCurHeader = header;  
  3.         int index = mHeaders.indexOf(header);  
  4.         if (index >= 0) {  
  5.             getListView().setItemChecked(index, true);  
  6.         } else {  
  7.             getListView().clearChoices();  
  8.         }  
  9.         showBreadCrumbs(header);  
  10.     }  

在这个方法中主要处理ListView的setItemChecked状态。如上图中蓝牙设置项的选中底色。并且设置Breadcrumb(标题)

2.5、

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. void showBreadCrumbs(Header header) {  
  2.         if (header != null) {  
  3.             CharSequence title = header.getBreadCrumbTitle(getResources());  
  4.             if (title == null) title = header.getTitle(getResources());  
  5.             if (title == null) title = getTitle();  
  6.             showBreadCrumbs(title, header.getBreadCrumbShortTitle(getResources()));  
  7.         } else {  
  8.             showBreadCrumbs(getTitle(), null);  
  9.         }  
  10.     }  

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. if (mFragmentBreadCrumbs == null) {  
  2.            View crumbs = findViewById(android.R.id.title);  
  3.            // For screens with a different kind of title, don't create breadcrumbs.  
  4.            try {  
  5.                mFragmentBreadCrumbs = (FragmentBreadCrumbs)crumbs;  
  6.            } catch (ClassCastException e) {  
  7.                return;  
  8.            }  
  9.            if (mFragmentBreadCrumbs == null) {  
  10.                if (title != null) {  
  11.                    setTitle(title);  
  12.                }  
  13.                return;  
  14.            }  
  15.            mFragmentBreadCrumbs.setMaxVisible(2);  
  16.            mFragmentBreadCrumbs.setActivity(this);  
  17.        }  
  18.        mFragmentBreadCrumbs.setTitle(title, shortTitle);  
  19.        mFragmentBreadCrumbs.setParentTitle(nullnullnull);  



 

 //*****************************************************************************************

2.6、在设置应用的源代码中,Settings.java类中。上述的处理存在如下差别。

Settings.java重新了switchHeader方法:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public void switchToHeader(Header header) {  
  2.         if (!mInLocalHeaderSwitch) {  
  3.             mCurrentHeader = null;  
  4.             mParentHeader = null;  
  5.         }  
  6.         super.switchToHeader(header);  
  7.     }  


mInLocalHeaderSwitch在我们点击条目的时候为false,故,Settings.java中定义的mCurrentHeader以及mParentHeader会赋值null。然后执行super.switchToHeader()。

 

 

 二、外部通过Action进入设置应用的流程。(多屏幕的状态下)

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. Intent intent=new Intent();  
  2. //      intent.setClassName(this, "c");  
  3. //      intent.setAction("android.intent.action.PICK_ACTIVITY");  
  4.         intent.setAction("android.settings.WIFI_IP_SETTINGS");  
  5.         startActivity(intent);  

通过上述代码,会进入如下界面。

 

启动这个界面会经历如下流程,

首先Settigns.java的onCreate方法。

1、

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. protected void onCreate(Bundle savedInstanceState) {  
  2.         if (getIntent().getBooleanExtra(EXTRA_CLEAR_UI_OPTIONS, false)) {  
  3.             getWindow().setUiOptions(0);  
  4.         }  
  5.   
  6.         getMetaData();  
  7.         mInLocalHeaderSwitch = true;  
  8.         super.onCreate(savedInstanceState);  
  9.         mInLocalHeaderSwitch = false;  
  10.   
  11.         if (!onIsHidingHeaders() && onIsMultiPane()) {  
  12.             highlightHeader();  
  13.             // Force the title so that it doesn't get overridden by a direct launch of  
  14.             // a specific settings screen.  
  15.             setTitle(R.string.settings_label);  
  16.         }  
  17.   
  18.         // Retrieve any saved state  
  19.         if (savedInstanceState != null) {  
  20.             mCurrentHeader = savedInstanceState.getParcelable(SAVE_KEY_CURRENT_HEADER);  
  21.             mParentHeader = savedInstanceState.getParcelable(SAVE_KEY_PARENT_HEADER);  
  22.         }  
  23.   
  24.         // If the current header was saved, switch to it  
  25.         if (savedInstanceState != null && mCurrentHeader != null) {  
  26.             //switchToHeaderLocal(mCurrentHeader);  
  27.             showBreadCrumbs(mCurrentHeader.title, null);  
  28.         }  
  29.   
  30.         if (mParentHeader != null) {  
  31.             setParentTitle(mParentHeader.title, nullnew OnClickListener() {  
  32.                 public void onClick(View v) {  
  33.                     switchToParent(mParentHeader.fragment);  
  34.                 }  
  35.             });  
  36.         }  
  37.   
  38.         // TODO Add support for android.R.id.home in all Setting's onOptionsItemSelected  
  39.         // getActionBar().setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP,  
  40.         // ActionBar.DISPLAY_HOME_AS_UP);  
  41.     }  

在这个方法内,首先执行getIntent方法,Settings重新了这个方法。

2、

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public Intent getIntent() {  
  2.         Intent superIntent = super.getIntent();  
  3.         String startingFragment = getStartingFragmentClass(superIntent);  
  4.         // This is called from super.onCreate, isMultiPane() is not yet reliable  
  5.         // Do not use onIsHidingHeaders either, which relies itself on this method  
  6.         if (startingFragment != null && !onIsMultiPane()) {  
  7.             Intent modIntent = new Intent(superIntent);  
  8.             modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);  
  9.             Bundle args = superIntent.getExtras();  
  10.             if (args != null) {  
  11.                 args = new Bundle(args);  
  12.             } else {  
  13.                 args = new Bundle();  
  14.             }  
  15.             args.putParcelable("intent", superIntent);  
  16.             modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, superIntent.getExtras());  
  17.             return modIntent;  
  18.         }  
  19.         return superIntent;  
  20.     }  

在这个方法内,会调用getStartingFragmentClass方法。

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. protected String getStartingFragmentClass(Intent intent) {  
  2.         if (mFragmentClass != nullreturn mFragmentClass;  
  3.   
  4.         String intentClass = intent.getComponent().getClassName();  
  5.         if (intentClass.equals(getClass().getName())) return null;  
  6.   
  7.         if ("com.android.settings.ManageApplications".equals(intentClass)  
  8.                 || "com.android.settings.RunningServices".equals(intentClass)  
  9.                 || "com.android.settings.applications.StorageUse".equals(intentClass)) {  
  10.             // Old names of manage apps.  
  11.             intentClass = com.android.settings.applications.ManageApplications.class.getName();  
  12.         }  
  13.   
  14.         return intentClass;  
  15.     }  

这个方法中,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方法。

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private void getMetaData() {  
  2.         try {  
  3.             ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),  
  4.                     PackageManager.GET_META_DATA);  
  5.             if (ai == null || ai.metaData == nullreturn;  
  6.             mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);  
  7.             mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);  
  8.               
  9.             // Check if it has a parent specified and create a Header object  
  10.             final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);  
  11.             String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);  
  12.             if (parentFragmentClass != null) {  
  13.                 mParentHeader = new Header();  
  14.                 mParentHeader.fragment = parentFragmentClass;  
  15.                 if (parentHeaderTitleRes != 0) {  
  16.                     mParentHeader.title = getResources().getString(parentHeaderTitleRes);  
  17.                 }  
  18.             }  
  19.         } catch (NameNotFoundException nnfe) {  
  20.             // No recovery  
  21.         }  
  22.     }  

这里,AdvancedWifiSettingsActivity在AndroidManifest.xml中的配置:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <activity android:name="Settings$AdvancedWifiSettingsActivity"  
  2.                 android:label="@string/wifi_advanced_settings_label"  
  3.                 android:configChanges="orientation|keyboardHidden|screenSize"  
  4.                 android:clearTaskOnLaunch="true">  
  5.             <intent-filter>  
  6.                 <action android:name="android.intent.action.MAIN" />  
  7.                 <action android:name="android.settings.WIFI_IP_SETTINGS" />  
  8.                 <category android:name="android.intent.category.VOICE_LAUNCH" />  
  9.                 <category android:name="android.intent.category.DEFAULT" />  
  10.             </intent-filter>  
  11.             <meta-data android:name="com.android.settings.FRAGMENT_CLASS"  
  12.                 android:value="com.android.settings.wifi.AdvancedWifiSettings" />  
  13.             <meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID"  
  14.                 android:resource="@id/wifi_settings" />  
  15.             <meta-data android:name="com.android.settings.PARENT_FRAGMENT_TITLE"  
  16.                 android:resource="@string/wifi_settings" />  
  17.             <meta-data android:name="com.android.settings.PARENT_FRAGMENT_CLASS"  
  18.                 android:value="com.android.settings.Settings$WifiSettingsActivity" />  
  19.         </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执行,接下来会执行:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. mInLocalHeaderSwitch = true;  
  2.         super.onCreate(savedInstanceState);  
  3.         mInLocalHeaderSwitch = false;  

这里会执行super.onCreate方法。之所以用mInLocalHeaderSwitch包裹,主要是因为super.onCreate方法,会执行到PreferenceActitivity.java中的 :

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. if (!mSinglePane) {  
  2.                         if (initialFragment == null) {  
  3.                             Header h = onGetInitialHeader();  
  4.                             switchToHeader(h);  
  5.                         } else {  
  6.                             switchToHeader(initialFragment, initialArguments);  
  7.                         }  
  8.                     }  

Settings.java重写了switchToHeader方法。

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public void switchToHeader(Header header) {  
  2.         if (!mInLocalHeaderSwitch) {  
  3.             mCurrentHeader = null;  
  4.             mParentHeader = null;  
  5.         }  
  6.         super.switchToHeader(header);  
  7.     }  

这样mInLocalHeaderSwitch为true,不会清楚mCurrentHeader以及mParentHeader。

最后会执行super.switchToHeader方法,这个方法的执行,会将AdvancedWifiSettings加载到如上图所示的右边的区域内。

 

Settings.java还重新了onGetInitialHeader方法,这个方法为Header赋了正确的值。

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public Header onGetInitialHeader() {  
  2.         String fragmentClass = getStartingFragmentClass(super.getIntent());  
  3.         if (fragmentClass != null) {  
  4.             Header header = new Header();  
  5.             header.fragment = fragmentClass;  
  6.             header.title = getTitle();  
  7.             header.fragmentArguments = getIntent().getExtras();  
  8.             mCurrentHeader = header;  
  9.             return header;  
  10.         }  
  11.   
  12.         return mFirstHeader;  
  13.     }  

5、最后一步,给上图左边的部分加上setItemChecked效果。也即是上图中的选中状态底纹。

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. if (!onIsHidingHeaders() && onIsMultiPane()) {  
  2.             highlightHeader();  
  3.             // Force the title so that it doesn't get overridden by a direct launch of  
  4.             // a specific settings screen.  
  5.             setTitle(R.string.settings_label);  
  6.         }  
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private void highlightHeader() {  
  2.         if (mTopLevelHeaderId != 0) {  
  3.             Integer index = mHeaderIndexMap.get(mTopLevelHeaderId);  
  4.             if (index != null) {  
  5.                 getListView().setItemChecked(index, true);  
  6.                 getListView().smoothScrollToPosition(index);  
  7.             }  
  8.         }  
  9.     }  


mTopLevelHeaderId,我们在getMeteData方法中得到。


一、在多屏幕中,mFirstHeader的作用主要是为了正确的切换第一个Header。

mFirstHeader的初始化

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. if (mFirstHeader == null &&  
  2.                         HeaderAdapter.getHeaderType(header) != HeaderAdapter.HEADER_TYPE_CATEGORY) {  
  3.                     mFirstHeader = header;  
  4.                 }  

如果为空,那么mFirstHeader为最靠前的第一个category。

mFirstHeader的使用:

  • [java] view plaincopy在CODE上查看代码片派生到我的代码片
    1. public Header onGetInitialHeader() {  
    2.         String fragmentClass = getStartingFragmentClass(super.getIntent());  
    3.         if (fragmentClass != null) {  
    4.             Header header = new Header();  
    5.             header.fragment = fragmentClass;  
    6.             header.title = getTitle();  
    7.             header.fragmentArguments = getIntent().getExtras();  
    8.             mCurrentHeader = header;  
    9.             return header;  
    10.         }  
    11.   
    12.         return mFirstHeader;  
    13.     }  

如果getStarttingFragmentClass为null,那么返回mFirstHeader。

  • [java] view plaincopy在CODE上查看代码片派生到我的代码片
    1. public void onNewIntent(Intent intent) {  
    2.         super.onNewIntent(intent);  
    3.   
    4.         // If it is not launched from history, then reset to top-level  
    5.         if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0  
    6.                 && mFirstHeader != null && !onIsHidingHeaders() && onIsMultiPane()) {  
    7.             switchToHeaderLocal(mFirstHeader);  
    8.         }  
    9.     }  

 二、mCurrentHeader的作用,显示当前Header的title。

初始化:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public Header onGetInitialHeader() {  
  2.         String fragmentClass = getStartingFragmentClass(super.getIntent());  
  3.         if (fragmentClass != null) {  
  4.             Header header = new Header();  
  5.             header.fragment = fragmentClass;  
  6.             header.title = getTitle();  
  7.             header.fragmentArguments = getIntent().getExtras();  
  8.             mCurrentHeader = header;  
  9.             return header;  
  10.         }  
  11.   
  12.         return mFirstHeader;  
  13.     }  

外部跳转得到了fragmentClass,那么会初始化mCurrentHeader。

另外的一处初始化:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private void switchToParent(String className) {  
  2.         final ComponentName cn = new ComponentName(this, className);  
  3.         try {  
  4.             final PackageManager pm = getPackageManager();  
  5.             final ActivityInfo parentInfo = pm.getActivityInfo(cn, PackageManager.GET_META_DATA);  
  6.   
  7.             if (parentInfo != null && parentInfo.metaData != null) {  
  8.                 String fragmentClass = parentInfo.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);  
  9.                 CharSequence fragmentTitle = parentInfo.loadLabel(pm);  
  10.                 Header parentHeader = new Header();  
  11.                 parentHeader.fragment = fragmentClass;  
  12.                 parentHeader.title = fragmentTitle;  
  13.                 mCurrentHeader = parentHeader;  
  14.   
  15.                 switchToHeaderLocal(parentHeader);  
  16.                 highlightHeader();  
  17.   
  18.                 mParentHeader = new Header();  
  19.                 mParentHeader.fragment  
  20.                         = parentInfo.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);  
  21.                 mParentHeader.title = parentInfo.metaData.getString(META_DATA_KEY_PARENT_TITLE);  
  22.             }  
  23.         } catch (NameNotFoundException nnfe) {  
  24.             Log.w(LOG_TAG, "Could not find parent activity : " + className);  
  25.         }  
  26.     }  

使用:

在onCreate中。

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. if (savedInstanceState != null) {  
  2.             mCurrentHeader = savedInstanceState.getParcelable(SAVE_KEY_CURRENT_HEADER);  
  3.             mParentHeader = savedInstanceState.getParcelable(SAVE_KEY_PARENT_HEADER);  
  4.         }  
  5.   
  6.         // If the current header was saved, switch to it  
  7.         if (savedInstanceState != null && mCurrentHeader != null) {  
  8.             //switchToHeaderLocal(mCurrentHeader);  
  9.             showBreadCrumbs(mCurrentHeader.title, null);  
  10.         }  


三、mParentHeader,

初始化:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private void getMetaData() {  
  2.         try {  
  3.             ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),  
  4.                     PackageManager.GET_META_DATA);  
  5.             if (ai == null || ai.metaData == nullreturn;  
  6.             mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);  
  7.             mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);  
  8.               
  9.             // Check if it has a parent specified and create a Header object  
  10.             final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);  
  11.             String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);  
  12.             if (parentFragmentClass != null) {  
  13.                 mParentHeader = new Header();  
  14.                 mParentHeader.fragment = parentFragmentClass;  
  15.                 if (parentHeaderTitleRes != 0) {  
  16.                     mParentHeader.title = getResources().getString(parentHeaderTitleRes);  
  17.                 }  
  18.             }  
  19.         } catch (NameNotFoundException nnfe) {  
  20.             // No recovery  
  21.         }  
  22.     }  


使用如上面的mCurrentHeader。

0 0
原创粉丝点击