Android Settings 修改

来源:互联网 发布:最优化 教材 编辑:程序博客网 时间:2024/05/01 16:52

  下面是Seeings应用的截图:

  可以看出这是很典型的使用了Fragment后的界面,设置里面有WIFI、蓝牙、显示、存储、应用等众多功能。左边的每一项,对应着右边的一个设置界面,Fragment有四个子类:DialogFragment, ListFragment, PreferenceFragment, WebViewFragment。很明显,Settings用的是PreferenceFragment。接着看一下Settings源码package结构:

   主题部分的实现主要在com.android.settings下面,其他包主要是用于各自功能实现,所以重点说这个包下面的类。在AndroidManifest.xml文字中,看到程序入口是Settings类:

   打开Settings类,是继承于PreferenceActivity:

   其他的继承关系如下:PreferenceActivity --> ListActivity --> Activity。PreferenceActivity主要用于Settings,关于如何使用可以参考API(http://developer.android.com/reference/android/preference/PreferenceActivity.html)以及guide(http://developer.android.com/guide/topics/ui/settings.html)。和它相关联的类有header、fragment、preference。每一个header就是左边的一个选项条目,像蓝牙、应用等,选择之后右边就会显示对应的fragment(平板),然后fragment和preference联系在一起,组成了一个个设置项。一般在activity中设置布局,用的是setContentView(),在PreferenceActivity中,是需要继承onBuildHeaders(List)这个方法,
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. @Override  
  2. ublic void onBuildHeaders(List<Header> target) {  
  3.   loadHeadersFromResource(R.xml.preference_headers, target);  
  4.    
  去生成选项表,点击选项表的一个条目,右边显示对应的Fragment,这就是很典型的header+fragment组合,所以如果想在Settings基础之上添加条目的话,在这个方法里面的xml文件中添加即可,然后对应上fragment。下面分析一下执行流程:
  首先进入onCreate(Bundle savedInstanceState)方法里面,代码如下:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. @Override  
  2.     protected void onCreate(Bundle savedInstanceState) {  
  3.         if (getIntent().getBooleanExtra(EXTRA_CLEAR_UI_OPTIONS, false)) {  
  4.             getWindow().setUiOptions(0);  
  5.         }  
  6.         mAuthenticatorHelper = new AuthenticatorHelper();  
  7.         mAuthenticatorHelper.updateAuthDescriptions(this);  
  8.         mAuthenticatorHelper.onAccountsUpdated(this, null);  
  9.         mDevelopmentPreferences = getSharedPreferences(DevelopmentSettings.PREF_FILE,  
  10.                 Context.MODE_PRIVATE);  
  11.         getMetaData();  
  12.         mInLocalHeaderSwitch = true;  
  13.         super.onCreate(savedInstanceState);  
  14.         mInLocalHeaderSwitch = false;  
  15.         if (!onIsHidingHeaders() && onIsMultiPane()) {  
  16.             highlightHeader(mTopLevelHeaderId);  
  17.             // Force the title so that it doesn't get overridden by a direct launch of  
  18.             // a specific settings screen.  
  19.             setTitle(R.string.settings_label);  
  20.         }  
  21.         // Retrieve any saved state  
  22.         if (savedInstanceState != null) {  
  23.             mCurrentHeader = savedInstanceState.getParcelable(SAVE_KEY_CURRENT_HEADER);  
  24.             mParentHeader = savedInstanceState.getParcelable(SAVE_KEY_PARENT_HEADER);  
  25.         }  
  26.         // If the current header was saved, switch to it  
  27.         if (savedInstanceState != null && mCurrentHeader != null) {  
  28.             //switchToHeaderLocal(mCurrentHeader);  
  29.             showBreadCrumbs(mCurrentHeader.title, null);  
  30.         }  
  31.         if (mParentHeader != null) {  
  32.             setParentTitle(mParentHeader.title, null, new OnClickListener() {  
  33.                 public void onClick(View v) {  
  34.                     switchToParent(mParentHeader.fragment);  
  35.                 }  
  36.             });  
  37.         }  
  38.         // Override up navigation for multi-pane, since we handle it in the fragment breadcrumbs  
  39.         if (onIsMultiPane()) {  
  40.             getActionBar().setDisplayHomeAsUpEnabled(false);  
  41.             getActionBar().setHomeButtonEnabled(false);  
  42.         }  
  43.     }  
  第一个if用于设置window ui的对修改来说不用考虑了,意义不大,
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. mAuthenticatorHelper = new AuthenticatorHelper();  
  2. mAuthenticatorHelper.updateAuthDescriptions(this);  
  3. mAuthenticatorHelper.onAccountsUpdated(this, null);  
  这个段代码用于认证以及更新账户信息,接着往下看:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. mDevelopmentPreferences = getSharedPreferences(DevelopmentSettings.PREF_FILE,Context.MODE_PRIVATE);  
  用于之后保存数据,然后是getMetaData();这个方法,代码如下:
[html] 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 == null) return;  
  6.             mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);  
  7.             mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);  
  8.             // Check if it has a parent specified and create a Header object  
  9.             final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);  
  10.             String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);  
  11.             if (parentFragmentClass != null) {  
  12.                 mParentHeader = new Header();  
  13.                 mParentHeader.fragment = parentFragmentClass;  
  14.                 if (parentHeaderTitleRes != 0) {  
  15.                     mParentHeader.title = getResources().getString(parentHeaderTitleRes);  
  16.                 }  
  17.             }  
  18.         } catch (NameNotFoundException nnfe) {  
  19.             // No recovery  
  20.         }  
  21.     }  
  这个方法用于设置mParentHeader的Fragment以及title。下面具体举两个例子,关于如何修改Settings。
一、添加headers
      header即是左边的菜单,如下图左侧。它的布局文件在res下的xml文件夹中,名字是settings_headers.xml。打开如下:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <!--  
  3.      Copyright (C) 2010 The Android Open Source Project  
  4.   
  5.      Licensed under the Apache License, Version 2.0 (the "License");  
  6.      you may not use this file except in compliance with the License.  
  7.      You may obtain a copy of the License at  
  8.   
  9.           http://www.apache.org/licenses/LICENSE-2.0  
  10.   
  11.      Unless required by applicable law or agreed to in writing, software  
  12.      distributed under the License is distributed on an "AS IS" BASIS,  
  13.      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
  14.      See the License for the specific language governing permissions and  
  15.      limitations under the License.  
  16. -->  
  17.   
  18. <preference-headers xmlns:android="http://schemas.android.com/apk/res/android" >  
  19.   
  20.     <!-- WIRELESS and NETWORKS -->  
  21.     <header  
  22.         android:id="@+id/wireless_section"  
  23.         android:title="@string/header_category_wireless_networks" />  
  24.   
  25.     <!-- Wifi -->  
  26.     <header  
  27.         android:id="@+id/wifi_settings"  
  28.         android:fragment="com.android.settings.wifi.WifiSettings"  
  29.         android:icon="@drawable/ic_settings_wireless"  
  30.         android:title="@string/wifi_settings_title" />  
  31.   
  32.     <!-- Bluetooth -->  
  33.     <header  
  34.         android:id="@+id/bluetooth_settings"  
  35.         android:fragment="com.android.settings.bluetooth.BluetoothSettings"  
  36.         android:icon="@drawable/ic_settings_bluetooth2"  
  37.         android:title="@string/bluetooth_settings_title" />  
  38.   
  39.     <!-- Data Usage -->  
  40.     <header  
  41.         android:id="@+id/data_usage_settings"  
  42.         android:fragment="com.android.settings.DataUsageSummary"  
  43.         android:icon="@drawable/ic_settings_data_usage"  
  44.         android:title="@string/data_usage_summary_title" />  
  45.   
  46.     <!-- Operator hook -->  
  47.     <header  
  48.         android:id="@+id/operator_settings"  
  49.         android:fragment="com.android.settings.WirelessSettings" >  
  50.         <intent android:action="com.android.settings.OPERATOR_APPLICATION_SETTING" />  
  51.     </header>  
  52.   
  53.     <!-- Other wireless and network controls -->  
  54.     <header  
  55.         android:id="@+id/wireless_settings"  
  56.         android:breadCrumbTitle="@string/wireless_networks_settings_title"  
  57.         android:fragment="com.android.settings.WirelessSettings"  
  58.         android:icon="@drawable/empty_icon"  
  59.         android:title="@string/radio_controls_title" />  
  60.   
  61.     <!-- DEVICE -->  
  62.     <header  
  63.         android:id="@+id/device_section"  
  64.         android:title="@string/header_category_device" />  
  65.   
  66.     <!-- Sound -->  
  67.     <header  
  68.         android:id="@+id/sound_settings"  
  69.         android:fragment="com.android.settings.SoundSettings"  
  70.         android:icon="@drawable/ic_settings_sound"  
  71.         android:title="@string/sound_settings" />  
  72.   
  73.     <!-- Display -->  
  74.     <header  
  75.         android:id="@+id/display_settings"  
  76.         android:fragment="com.android.settings.DisplaySettings"  
  77.         android:icon="@drawable/ic_settings_display"  
  78.         android:title="@string/display_settings" />  
  79.   
  80.     <!-- Storage -->  
  81.     <header  
  82.         android:id="@+id/storage_settings"  
  83.         android:fragment="com.android.settings.deviceinfo.Memory"  
  84.         android:icon="@drawable/ic_settings_storage"  
  85.         android:title="@string/storage_settings" />  
  86.   
  87.     <!-- Battery -->  
  88.     <header  
  89.         android:id="@+id/battery_settings"  
  90.         android:fragment="com.android.settings.fuelgauge.PowerUsageSummary"  
  91.         android:icon="@drawable/ic_settings_battery"  
  92.         android:title="@string/power_usage_summary_title" />  
  93.   
  94.     <!-- Application Settings -->  
  95.     <header  
  96.         android:id="@+id/application_settings"  
  97.         android:fragment="com.android.settings.applications.ManageApplications"  
  98.         android:icon="@drawable/ic_settings_applications"  
  99.         android:title="@string/applications_settings" />  
  100.   
  101.     <!-- Manage users -->  
  102.     <header  
  103.         android:id="@+id/user_settings"  
  104.         android:fragment="com.android.settings.users.UserSettings"  
  105.         android:icon="@drawable/ic_settings_multiuser"  
  106.         android:title="@string/user_settings_title" />  
  107.   
  108.     <!-- Manufacturer hook -->  
  109.     <header  
  110.         android:id="@+id/manufacturer_settings"  
  111.         android:fragment="com.android.settings.WirelessSettings" >  
  112.         <intent android:action="com.android.settings.MANUFACTURER_APPLICATION_SETTING" />  
  113.     </header>  
  114.   
  115.     <!-- PERSONAL -->  
  116.     <header  
  117.         android:id="@+id/personal_section"  
  118.         android:title="@string/header_category_personal" />  
  119.   
  120.     <!-- Location -->  
  121.     <header  
  122.         android:id="@+id/location_settings"  
  123.         android:fragment="com.android.settings.LocationSettings"  
  124.         android:icon="@drawable/ic_settings_location"  
  125.         android:title="@string/location_settings_title" />  
  126.   
  127.     <!-- Security -->  
  128.     <header  
  129.         android:id="@+id/security_settings"  
  130.         android:fragment="com.android.settings.SecuritySettings"  
  131.         android:icon="@drawable/ic_settings_security"  
  132.         android:title="@string/security_settings_title" />  
  133.   
  134.     <!-- Language -->  
  135.     <header  
  136.         android:id="@+id/language_settings"  
  137.         android:fragment="com.android.settings.inputmethod.InputMethodAndLanguageSettings"  
  138.         android:icon="@drawable/ic_settings_language"  
  139.         android:title="@string/language_settings" />  
  140.   
  141.     <!-- Backup and reset -->  
  142.     <header  
  143.         android:id="@+id/privacy_settings"  
  144.         android:fragment="com.android.settings.PrivacySettings"  
  145.         android:icon="@drawable/ic_settings_backup"  
  146.         android:title="@string/privacy_settings" />  
  147.     <header  
  148.         android:id="@+id/kytusers_settings"  
  149.         android:fragment="com.android.settings.KytUsersSettings"  
  150.         android:icon="@drawable/ic_settings_backup"  
  151.         android:title="考易通账户" />  
  152.   
  153.     <!-- ACCOUNTS section -->  
  154.     <header  
  155.         android:id="@+id/account_settings"  
  156.         android:title="@string/account_settings" />  
  157.     <header  
  158.         android:id="@+id/account_add"  
  159.         android:icon="@drawable/ic_menu_add"  
  160.         android:title="@string/add_account_label" >  
  161.         <intent android:action="android.settings.ADD_ACCOUNT_SETTINGS" />  
  162.     </header>  
  163.   
  164.     <!-- SYSTEM -->  
  165.     <header  
  166.         android:id="@+id/system_section"  
  167.         android:title="@string/header_category_system" />  
  168.   
  169.     <!-- Date & Time -->  
  170.     <header  
  171.         android:id="@+id/date_time_settings"  
  172.         android:fragment="com.android.settings.DateTimeSettings"  
  173.         android:icon="@drawable/ic_settings_date_time"  
  174.         android:title="@string/date_and_time_settings_title" />  
  175.   
  176.     <!-- Accessibility feedback -->  
  177.     <header  
  178.         android:id="@+id/accessibility_settings"  
  179.         android:fragment="com.android.settings.AccessibilitySettings"  
  180.         android:icon="@drawable/ic_settings_accessibility"  
  181.         android:title="@string/accessibility_settings" />  
  182.   
  183.     <!-- Development -->  
  184.     <header  
  185.         android:id="@+id/development_settings"  
  186.         android:fragment="com.android.settings.DevelopmentSettings"  
  187.         android:icon="@drawable/ic_settings_development"  
  188.         android:title="@string/development_settings_title" />  
  189.   
  190.     <!-- About Device -->  
  191.     <header  
  192.         android:id="@+id/about_settings"  
  193.         android:fragment="com.android.settings.DeviceInfoSettings"  
  194.         android:icon="@drawable/ic_settings_about"  
  195.         android:title="@string/about_settings" />  
  196.   
  197. </preference-headers>  
  这些header分别对应着各自的菜单,如果想要添加还是删除就在这里修改即可。比如我们不想要蓝牙模块了,那就直接把下面这个header删除即可,添加的话类似。
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <!-- Bluetooth -->  
  2.   <header  
  3.       android:id="@+id/bluetooth_settings"  
  4.       android:fragment="com.android.settings.bluetooth.BluetoothSettings"  
  5.       android:icon="@drawable/ic_settings_bluetooth2"  
  6.       android:title="@string/bluetooth_settings_title" />  
   如果是做添加操作的话,不要忘了创建你的PreferenceFragment,然后在header里面添加id、fragment、icon、title等,如上面那样。
  
二、修改显示的应用
      先看一下应用显示的部分:
  看一下在源码中对应的包:

   应用显示是一个滑动的界面,猜测是用ViewPager实现的,下面开始寻找实现。首先进入xml文件夹找到settings_headers,找到这一段代码:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <!-- Application Settings -->  
  2.  <header  
  3.      android:id="@+id/application_settings"  
  4.      android:fragment="com.android.settings.applications.ManageApplications"  
  5.      android:icon="@drawable/ic_settings_applications"  
  6.      android:title="@string/applications_settings" />  
  然后打开对应的fragment,ManageApplications。发现这个它是继承于Fragment
  既然继承于Fragment,那就直接定位到onCreate()方法,
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. @Override  
  2.    public void onCreate(Bundle savedInstanceState) {  
  3.        super.onCreate(savedInstanceState);  
  4.   
  5.        setHasOptionsMenu(true);  
  6.   
  7.        mApplicationsState = ApplicationsState.getInstance(getActivity().getApplication());  
  8.        Intent intent = getActivity().getIntent();  
  9.        String action = intent.getAction();  
  10.        int defaultListType = LIST_TYPE_DOWNLOADED;  
  11.        String className = getArguments() != null  
  12.                ? getArguments().getString("classname") : null;  
  13.        if (className == null) {  
  14.            className = intent.getComponent().getClassName();  
  15.        }  
  16.        if (className.equals(RunningServicesActivity.class.getName())  
  17.                || className.endsWith(".RunningServices")) {  
  18.            defaultListType = LIST_TYPE_RUNNING;  
  19.        } else if (className.equals(StorageUseActivity.class.getName())  
  20.                || Intent.ACTION_MANAGE_PACKAGE_STORAGE.equals(action)  
  21.                || className.endsWith(".StorageUse")) {  
  22.            mSortOrder = SORT_ORDER_SIZE;  
  23.            defaultListType = LIST_TYPE_ALL;  
  24.        } else if (Settings.ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS.equals(action)) {  
  25.            // Select the all-apps list, with the default sorting  
  26.            defaultListType = LIST_TYPE_ALL;  
  27.        }  
  28.   
  29.        if (savedInstanceState != null) {  
  30.            mSortOrder = savedInstanceState.getInt(EXTRA_SORT_ORDER, mSortOrder);  
  31.            int tmp = savedInstanceState.getInt(EXTRA_DEFAULT_LIST_TYPE, -1);  
  32.            if (tmp != -1) defaultListType = tmp;  
  33.            mShowBackground = savedInstanceState.getBoolean(EXTRA_SHOW_BACKGROUND, false);  
  34.        }  
  35.   
  36.        mDefaultListType = defaultListType;  
  37.   
  38.        final Intent containerIntent = new Intent().setComponent(  
  39.                StorageMeasurement.DEFAULT_CONTAINER_COMPONENT);  
  40.        getActivity().bindService(containerIntent, mContainerConnection, Context.BIND_AUTO_CREATE);  
  41.   
  42.        mInvalidSizeStr = getActivity().getText(R.string.invalid_size_value);  
  43.        mComputingSizeStr = getActivity().getText(R.string.computing_size);  
  44.   
  45.        TabInfo tab = new TabInfo(this, mApplicationsState,  
  46.                getActivity().getString(R.string.filter_apps_third_party),  
  47.                LIST_TYPE_DOWNLOADED, this, savedInstanceState);  
  48.        mTabs.add(tab);  
  49.   
  50.        if (!Environment.isExternalStorageEmulated()) {  
  51.            tab = new TabInfo(this, mApplicationsState,  
  52.                    getActivity().getString(R.string.filter_apps_onsdcard),  
  53.                    LIST_TYPE_SDCARD, this, savedInstanceState);  
  54.            mTabs.add(tab);  
  55.        }  
  56.   
  57.        tab = new TabInfo(this, mApplicationsState,  
  58.                getActivity().getString(R.string.filter_apps_running),  
  59.                LIST_TYPE_RUNNING, this, savedInstanceState);  
  60.        mTabs.add(tab);  
  61.   
  62.        tab = new TabInfo(this, mApplicationsState,  
  63.                getActivity().getString(R.string.filter_apps_all),  
  64.                LIST_TYPE_ALL, this, savedInstanceState);  
  65.        mTabs.add(tab);  
  66.    }  
  这里主要是初始化TabInfo的数据,之后显示程序的时候会用到。接下来定位到onCreateView()方法,这个方法主要是初始化界面,
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. @Override  
  2.     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  
  3.         // initialize the inflater  
  4.         mInflater = inflater;  
  5.   
  6.         View rootView = mInflater.inflate(R.layout.manage_applications_content,  
  7.                 container, false);  
  8.         mContentContainer = container;  
  9.         mRootView = rootView;  
  10.   
  11.         mViewPager = (ViewPager) rootView.findViewById(R.id.pager);  
  12.         MyPagerAdapter adapter = new MyPagerAdapter();  
  13.         mViewPager.setAdapter(adapter);  
  14.         mViewPager.setOnPageChangeListener(adapter);  
  15.         PagerTabStrip tabs = (PagerTabStrip) rootView.findViewById(R.id.tabs);  
  16.         tabs.setTabIndicatorColorResource(android.R.color.holo_blue_light);  
  17.   
  18.         // We have to do this now because PreferenceFrameLayout looks at it  
  19.         // only when the view is added.  
  20.         if (container instanceof PreferenceFrameLayout) {  
  21.             ((PreferenceFrameLayout.LayoutParams) rootView.getLayoutParams()).removeBorders = true;  
  22.         }  
  23.   
  24.         if (savedInstanceState != null && savedInstanceState.getBoolean(EXTRA_RESET_DIALOG)) {  
  25.             buildResetDialog();  
  26.         }  
  27.   
  28.         if (savedInstanceState == null) {  
  29.             // First time init: make sure view pager is showing the correct tab.  
  30.             for (int i = 0; i < mTabs.size(); i++) {  
  31.                 TabInfo tab = mTabs.get(i);  
  32.                 if (tab.mListType == mDefaultListType) {  
  33.                     mViewPager.setCurrentItem(i);  
  34.                     break;  
  35.                 }  
  36.             }  
  37.         }  
  38.   
  39.         return rootView;  
  40.     }  
  可以看到,正是使用了ViewPager,另外还有PagerTabStrip。先看一下最下面的:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. if (savedInstanceState == null) {  
  2.           // First time init: make sure view pager is showing the correct tab.  
  3.           for (int i = 0; i < mTabs.size(); i++) {  
  4.               TabInfo tab = mTabs.get(i);  
  5.               if (tab.mListType == mDefaultListType) {  
  6.                   mViewPager.setCurrentItem(i);  
  7.                   break;  
  8.               }  
  9.           }  
  10.       }  
  这段代码的作用就是用于设置默认显示哪个选项卡的程序,所以就是“已下载”这个界面。然后回过头看一下上面的代码,
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. MyPagerAdapter adapter = new MyPagerAdapter();  
  2.         mViewPager.setAdapter(adapter);  
  这个就是熟悉的适配器了,所以显示程序的数据在这里面。开打这个类,
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. class MyPagerAdapter extends PagerAdapter  
  2.             implements ViewPager.OnPageChangeListener {  
  3.         int mCurPos = 0;  
  4.   
  5.         @Override  
  6.         public int getCount() {  
  7.             return mTabs.size();  
  8.         }  
  9.           
  10.         @Override  
  11.         public Object instantiateItem(ViewGroup container, int position) {  
  12.             TabInfo tab = mTabs.get(position);  
  13.             View root = tab.build(mInflater, mContentContainer, mRootView);  
  14.             container.addView(root);  
  15.             return root;  
  16.         }  
  17.   
  18.         @Override  
  19.         public void destroyItem(ViewGroup container, int position, Object object) {  
  20.             container.removeView((View)object);  
  21.         }  
  22.   
  23.         @Override  
  24.         public boolean isViewFromObject(View view, Object object) {  
  25.             return view == object;  
  26.         }  
  27.   
  28.         @Override  
  29.         public CharSequence getPageTitle(int position) {  
  30.             return mTabs.get(position).mLabel;  
  31.         }  
  32.   
  33.         @Override  
  34.         public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {  
  35.         }  
  36.   
  37.         @Override  
  38.         public void onPageSelected(int position) {  
  39.             mCurPos = position;  
  40.         }  
  41.   
  42.         @Override  
  43.         public void onPageScrollStateChanged(int state) {  
  44.             if (state == ViewPager.SCROLL_STATE_IDLE) {  
  45.                 updateCurrentTab(mCurPos);  
  46.             }  
  47.         }  
  48.     }  
  可以看到,有几个滑动的页卡,是通过mTabs这个类来控制的,而它就是TabInfo类型。接着看一下绘制视图的方法:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. MyPagerAdapter  @Override  
  2.         public Object instantiateItem(ViewGroup container, int position) {  
  3.             TabInfo tab = mTabs.get(position);  
  4.             View root = tab.build(mInflater, mContentContainer, mRootView);  
  5.             container.addView(root);  
  6.             return root;  
  7.         }  
   首先是获取到一个tab,然后这个tab用它的build()方法去生成一个视图,最后放到ViewPager显示。所以问题的重点分析就是TabInfo这个类了。先说buid()方法,
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public View build(LayoutInflater inflater, ViewGroup contentParent,  
  2.                View contentChild) {  
  3.            if (mRootView != null) {  
  4.                return mRootView;  
  5.            }  
  6.   
  7.            mInflater = inflater;  
  8.            mRootView = inflater  
  9.                    .inflate(  
  10.                            mListType == LIST_TYPE_RUNNING ? R.layout.manage_applications_running  
  11.                                    : R.layout.manage_applications_apps, null);  
  12.            mLoadingContainer = mRootView.findViewById(R.id.loading_container);  
  13.            mLoadingContainer.setVisibility(View.VISIBLE);  
  14.            mListContainer = mRootView.findViewById(R.id.list_container);  
  15.            if (mListContainer != null) {  
  16.                // Create adapter and list view here  
  17.                View emptyView = mListContainer  
  18.                        .findViewById(com.android.internal.R.id.empty);  
  19.                ListView lv = (ListView) mListContainer  
  20.                        .findViewById(android.R.id.list);  
  21.                if (emptyView != null) {  
  22.                    lv.setEmptyView(emptyView);  
  23.                }  
  24.                lv.setOnItemClickListener(this);  
  25.                lv.setSaveEnabled(true);  
  26.                lv.setItemsCanFocus(true);  
  27.                lv.setTextFilterEnabled(true);  
  28.                mListView = lv;  
  29.                mApplications = new ApplicationsAdapter(mApplicationsState,  
  30.                        this, mFilter);  
  31.                mListView.setAdapter(mApplications);  
  32.                mListView.setRecyclerListener(mApplications);  
  33.                mColorBar = (LinearColorBar) mListContainer  
  34.                        .findViewById(R.id.storage_color_bar);  
  35.                mStorageChartLabel = (TextView) mListContainer  
  36.                        .findViewById(R.id.storageChartLabel);  
  37.                mUsedStorageText = (TextView) mListContainer  
  38.                        .findViewById(R.id.usedStorageText);  
  39.                mFreeStorageText = (TextView) mListContainer  
  40.                        .findViewById(R.id.freeStorageText);  
  41.                Utils.prepareCustomPreferencesList(contentParent, contentChild,  
  42.                        mListView, false);  
  43.                if (mFilter == FILTER_APPS_SDCARD) {  
  44.                    mStorageChartLabel.setText(mOwner.getActivity().getText(  
  45.                            R.string.sd_card_storage));  
  46.                } else {  
  47.                    mStorageChartLabel.setText(mOwner.getActivity().getText(  
  48.                            R.string.internal_storage));  
  49.                }  
  50.                applyCurrentStorage();  
  51.            }  
  52.            mRunningProcessesView = (RunningProcessesView) mRootView  
  53.                    .findViewById(R.id.running_processes);  
  54.            if (mRunningProcessesView != null) {  
  55.                mRunningProcessesView.doCreate(mSavedInstanceState);  
  56.            }  
  57.   
  58.            return mRootView;  
  59.        }  
  第四行是生成了一view对象,
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. mRootView = inflater.inflate(mListType == LIST_TYPE_RUNNING ? R.layout.manage_applications_running: R.layout.manage_applications_apps, null);  
  这行代码用来判断加载哪个布局文件,确实viewpager虽然动态显示四个页面,但是其中三个的布局是一样的,唯一不一样的就是显示正在运行的界面。
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. ListView lv = (ListView) mListContainer  
  2.                         .findViewById(android.R.id.list);  
  3.                 if (emptyView != null) {  
  4.                     lv.setEmptyView(emptyView);  
  5.                 }  
  6.                 lv.setOnItemClickListener(this);  
  7.                 lv.setSaveEnabled(true);  
  8.                 lv.setItemsCanFocus(true);  
  9.                 lv.setTextFilterEnabled(true);  
  10.                 mListView = lv;  
  11.                 mApplications = new ApplicationsAdapter(mApplicationsState,  
  12.                         this, mFilter);  
  13.                 mListView.setAdapter(mApplications);  
  这段代码就是用于显示app程序了,然后定位到ApplicationsAdapter这个类,在它的构造方法里面,传入三个参数。一个是mApplicationsState对象,以后用于对ApplicationsState类进行操作;一个是TabInfo,用来显示不同的界面;一个是过滤器,是标识显示哪个界面。进入这个构造方法,
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public ApplicationsAdapter(ApplicationsState state, TabInfo tab,  
  2.              int filterMode) {  
  3.          mState = state;  
  4.          mSession = state.newSession(this);  
  5.          mTab = tab;  
  6.          mContext = tab.mOwner.getActivity();  
  7.          mFilterMode = filterMode;  
  8.      }  
   发现没有在这里传入什么数据,然后看一下ApplicationsAdapter这个类,发现它继承了三个接口,第一个是过滤用的,第三个是系统SDK接口用于ListView循环处理。而第二个接口正是负责处理数据的,
  它有六个回调方法:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public static interface Callbacks {  
  2.        public void onRunningStateChanged(boolean running);  
  3.   
  4.        public void onPackageListChanged();  
  5.   
  6.        public void onRebuildComplete(ArrayList<AppEntry> apps);  
  7.   
  8.        public void onPackageIconChanged();  
  9.   
  10.        public void onPackageSizeChanged(String packageName);  
  11.   
  12.        public void onAllSizesComputed();  
  13.    }  
  第三个回调方法onRebuildComplete(ArrayList<AppEntry> apps)正是用于返回app Entities的,但是到这里如果我们还是按这条线是分析不下去了,找不到这个数据是从哪里来的。所以不能按照这个思路往下走了,也就是说app程序数据不是在这里获取的,那会是什么地方呢?一般情况下,我们是在onStart或者onCreat方法里面,但是Setting里面都没有这样做,那往下看一下onResume吧。果然Settings是在这个方法里面加载数据的,
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. @Override  
  2. public void onResume() {  
  3.     super.onResume();  
  4.     mActivityResumed = true;  
  5.     updateCurrentTab(mViewPager.getCurrentItem());  
  6.     updateOptionsMenu();  
  7. }  
  首先是调用了updateCurrentTab(mViewPager.getCurrentItem())方法,然后updateCurrentTab方法里面又调用了TabInfo的resume方法,在TabInfo的resume方法里面接着调用了ApplicationsAdapter 的resume方法,又在ApplicationsAdapter 的resume方法里面调用Session的resume方法,最后又在Session的resume方法里面调用doResumeIfNeededLocked()方法,这个方法就是从系统读取程序信息的,代码如下:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. void doResumeIfNeededLocked() {  
  2.         if (mResumed) {  
  3.             return;  
  4.         }  
  5.         mResumed = true;  
  6.         if (mPackageIntentReceiver == null) {  
  7.             mPackageIntentReceiver = new PackageIntentReceiver();  
  8.             mPackageIntentReceiver.registerReceiver();  
  9.         }  
  10.         //这个mApplications就是所有程序数据,如果你想过滤哪些程序的信息,对这个集合进行修改即可。比如你在做定制机的时候,不想自己的程序显示在Settings里面,那就在这里修改。  
  11.         mApplications = mPm.getInstalledApplications(mRetrieveFlags);  
  12.         if (mApplications == null) {  
  13.             mApplications = new ArrayList<ApplicationInfo>();  
  14.         }  
  15.   
  16.         if (mInterestingConfigChanges.applyNewConfig(mContext.getResources())) {  
  17.             // If an interesting part of the configuration has changed, we  
  18.             // should completely reload the app entries.  
  19.             mEntriesMap.clear();  
  20.             mAppEntries.clear();  
  21.         } else {  
  22.             for (int i = 0; i < mAppEntries.size(); i++) {  
  23.                 mAppEntries.get(i).sizeStale = true;  
  24.             }  
  25.         }  
  26.   
  27.         for (int i = 0; i < mApplications.size(); i++) {  
  28.             final ApplicationInfo info = mApplications.get(i);  
  29.             // Need to trim out any applications that are disabled by  
  30.             // something different than the user.  
  31.             if (!info.enabled  
  32.                     && info.enabledSetting != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {  
  33.                 mApplications.remove(i);  
  34.                 i--;  
  35.                 continue;  
  36.             }  
  37.             final AppEntry entry = mEntriesMap.get(info.packageName);  
  38.             if (entry != null) {  
  39.                 entry.info = info;  
  40.             }  
  41.         }  
  42.         mCurComputingSizePkg = null;  
  43.         if (!mBackgroundHandler.hasMessages(BackgroundHandler.MSG_LOAD_ENTRIES)) {  
  44.             mBackgroundHandler  
  45.                     .sendEmptyMessage(BackgroundHandler.MSG_LOAD_ENTRIES);  
  46.         }  
  47.     };  
   至此,完成了显示程序的剖析,其他模块类似,只要按照流程走就行了。

相似博文推荐:
  1、Android PreferenceActivity点击Header是如何处理的?
  2、android-setting
  3、Android4.0设置界面修改总结
  4、Android源码之“应用程序界面“分析一( 从settings开始)
  5、Android 应用程序分析之Settings
  6、菜鸟Android4.0 Settings分析(一)
  7、Android Settings源码结构分析与自实现
  8、Settings源码分析
  9、Settings修改记录

0 0
原创粉丝点击