Android5.0 Lollipop Setting启动分析

1.Android5.0和前版本的Setting实现方式有区别,需要看较早版本的请戳http://blog.csdn.net/wangjinyu501/article/details/22077803
2.本文主要是对Setting的启动进行大致分析

1.总概况

本文只分析启动过程

2.Settings初始化流程

首先根据manifest文件找出最先启动的activity:Settings。该类具体代码如下:
public class Settings extends SettingsActivity {

    /*
    * Settings subclasses for launching independently.
    */
    public static class BluetoothSettingsActivity extends SettingsActivity { /* empty */ }
    public static class WirelessSettingsActivity extends SettingsActivity { /* empty */ }
    public static class SimSettingsActivity extends SettingsActivity { /* empty */ }
    public static class AppOpsSummaryActivity extends SettingsActivity {
        @Override
        public boolean isValidFragment(String className) {
            if (AppOpsSummary.class.getName().equals(className)) {
                return true;
            }
            return super.isValidFragment(className);
            }
    }
    public static class StorageUseActivity extends SettingsActivity { /* empty */ }
    public static class OtherSoundSettingsActivity extends SettingsActivity { /* empty */ }
    public static class QuickLaunchSettingsActivity extends SettingsActivity { /* empty */ }

    public static class TopLevelSettings extends SettingsActivity { /* empty */ }
    public static class ApnSettingsActivity extends SettingsActivity { /* empty */ }
}


可以看出Setting类主要是继承了SettingsActivity,然后创建了很多的内部类。直接转到SettingsActivity。既然是Activity直奔onCreate方法。
getMetaData();//此函数在初始化时会直接返回

mIsShowingDashboard = className.equals(Settings.class.getName());//此时className和Settings.class一致,为true;

 setContentView(mIsShowingDashboard   ?  R.layout.settings_main_dashboard : R.layout.settings_main_prefs);  

   
终于加载xml文件了,可知本次加载的是 R.layout.settings_main_dashboard,该xml文件代码如下:
<?xml version="1.0" encoding="utf-8"?>

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
             android:id="@+id/main_content"
             android:layout_height="match_parent"
             android:layout_width="match_parent"
             android:background="@color/dashboard_background_color"
             />

       除了一个FrameLayout什么都没有,猜测setting的很多设置项就是放在了这个id为main_content的FrameLayout中显示的。继续onCreate方法
<span style="white-space:pre">		</span>mDisplayHomeAsUpEnabled = false;
                mDisplaySearch = true;
                mInitialTitleResId = R.string.dashboard_title;// <string name="dashboard_title">Settings</string>
                switchToFragment(DashboardSummary.class.getName(), null, false, false,mInitialTitleResId, mInitialTitle, false);


重点在 switchToFragment这个函数,猜测是将一个Fragment放在前文提到的id为main_content的FrameLayout中。

private Fragment switchToFragment(String fragmentName, Bundle args, boolean validate,
            boolean addToBackStack, int titleResId, CharSequence title, boolean withTransition) {
        if (validate && !isValidFragment(fragmentName)) {
            throw new IllegalArgumentException("Invalid fragment for this activity: "
                    + fragmentName);
        }
        Fragment f = Fragment.instantiate(this, fragmentName, args);//通过静态方法实例化一个fragment
        FragmentTransaction transaction = getFragmentManager().beginTransaction();//获取fragment操作集合
        transaction.replace(R.id.main_content, f);//将原容器中的内容替换为f
        if (withTransition) {
            TransitionManager.beginDelayedTransition(mContent);
        }
        if (addToBackStack) {
        	//在commit()方法之前,你可以调用addToBackStack(),把这个transaction加入back stack中去,这样按返回键时会出现被替换的fragment
            transaction.addToBackStack(SettingsActivity.BACK_STACK_PREFS);
        }
        if (titleResId > 0) {
            transaction.setBreadCrumbTitle(titleResId);
        } else if (title != null) {
            transaction.setBreadCrumbTitle(title);
        }
        transaction.commitAllowingStateLoss();
        getFragmentManager().executePendingTransactions();//调用commit()方法并不能立即执行transaction中包含的改变动作,commit()方法把transaction加入activity的UI线程队列中。

      // 但是,如果觉得有必要的话,可以调用executePendingTransactions()方法来立即执行commit()提供的transaction。
        return f;
    }
上述过程较为简单,核心就一句代码 transaction.replace(R.id.main_content, f),这句就是将f这个fragment放入id为main_content的FrameLayout中。那现在问题又来了,放入的这个名为 DashboardSummary的fragment又是什么呢?下面进入 DashboardSummary的分析。既然是fragment,抓住主要的几个方法就好了。
先看onCreateView:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        mLayoutInflater = inflater;
        final View rootView = inflater.inflate(R.layout.dashboard, container, false);
        mDashboard = (ViewGroup) rootView.findViewById(R.id.dashboard_container);
      return rootView;
    }

就是加载一个R.layout.dashboard然后找出其中的dashboard_container。那看看这个dashboard是什么

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/dashboard"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scrollbarStyle="outsideOverlay"
    android:clipToPadding="false">

        <LinearLayout
                android:id="@+id/dashboard_container"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_gravity="center_horizontal"
                android:paddingStart="@dimen/dashboard_padding_start"
                android:paddingEnd="@dimen/dashboard_padding_end"
                android:paddingTop="@dimen/dashboard_padding_top"
                android:paddingBottom="@dimen/dashboard_padding_bottom"
                android:orientation="vertical"
                />

</ScrollView>
也很简单,就是一个id为dashboard_container的LinearLayout,猜测这个dashboard_container为真正放置设置项的地方。既然onCreateView中没有,就到onResume中去找。
 public void onResume() {
        super.onResume();
        sendRebuildUI();
        final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
        filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
        filter.addDataScheme("package");
        getActivity().registerReceiver(mHomePackageReceiver, filter);
    }

进入sendRebuildUI
private void sendRebuildUI() {
        if (!mHandler.hasMessages(MSG_REBUILD_UI)) {
            mHandler.sendEmptyMessage(MSG_REBUILD_UI);
        }
    }
发送一个MSG_REBUILD_UI的消息;如何处理呢?
		switch (msg.what) {
                		case MSG_REBUILD_UI: {
                 		   final Context context = getActivity();
                 		   rebuildUI(context);
               		 } break;
调用rebuildUI方法:
 private void rebuildUI(Context context) {
        if (!isAdded()) {
            Log.w(LOG_TAG, "Cannot build the DashboardSummary UI yet as the Fragment is not added");
            return;
        }
        long start = System.currentTimeMillis();
        final Resources res = getResources();
        mDashboard.removeAllViews();

        List<DashboardCategory> categories =
                ((SettingsActivity) context).getDashboardCategories(true);//非常重要的一句,获取DashboardCategory
        final int count = categories.size();
        for (int n = 0; n < count; n++) {
            DashboardCategory category = categories.get(n);
            View categoryView = mLayoutInflater.inflate(R.layout.dashboard_category, mDashboard,
                    false);
            TextView categoryLabel = (TextView) categoryView.findViewById(R.id.category_title);
            categoryLabel.setText(category.getTitle(res));
            ViewGroup categoryContent =
                    (ViewGroup) categoryView.findViewById(R.id.category_content);
            final int tilesCount = category.getTilesCount();
            for (int i = 0; i < tilesCount; i++) {
                DashboardTile tile = category.getTile(i);
                DashboardTileView tileView = new DashboardTileView(context);
                updateTileView(context, res, tile, tileView.getImageView(),
                        tileView.getTitleTextView(), tileView.getStatusTextView());
                tileView.setTile(tile);
                categoryContent.addView(tileView);
            }

            // Add the category
            mDashboard.addView(categoryView);
        }
        long delta = System.currentTimeMillis() - start;
        Log.d(LOG_TAG, "rebuildUI took: " + delta + " ms");
    }
这段代码就是加载设置界面的:将每一个DashboardCategory取出,并且找出其中包含的DashboardTile形成DashboardTileView,最后显示在界面。
但是到底加进去的是什么呢?
秘密在getDashboardCategories()这里,经过一系列调用后,会调用 loadCategoriesFromResource(R.xml.dashboard_categories, categories);
而dashboard_categories:
<dashboard-categories
        xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- WIRELESS and NETWORKS -->
    <dashboard-category
            android:id="@+id/wireless_section"
            android:title="@string/header_category_wireless_networks" >

        <!-- Wifi -->
        <dashboard-tile
                android:id="@+id/wifi_settings"
                android:title="@string/wifi_settings_title"
                android:fragment="com.android.settings.wifi.WifiSettings"
                android:icon="@drawable/ic_settings_wireless"
                />

        <!-- Bluetooth -->
        <dashboard-tile
                android:id="@+id/bluetooth_settings"
                android:title="@string/bluetooth_settings_title"
                android:fragment="com.android.settings.bluetooth.BluetoothSettings"
                android:icon="@drawable/ic_settings_bluetooth2"
                />

        <!-- SIM Cards -->
        <dashboard-tile
                android:id="@+id/sim_settings"
                android:title="@string/sim_settings_title"
                android:fragment="com.android.settings.sim.SimSettings"
                android:icon="@drawable/ic_sim_sd"
                />

        <!-- Data Usage -->
        <dashboard-tile
                android:id="@+id/data_usage_settings"
                android:title="@string/data_usage_summary_title"
                android:fragment="com.android.settings.DataUsageSummary"
                android:icon="@drawable/ic_settings_data_usage"
                />

        <!-- Operator hook -->
        <dashboard-tile
                android:id="@+id/operator_settings"
                android:fragment="com.android.settings.WirelessSettings" >
            <intent android:action="com.android.settings.OPERATOR_APPLICATION_SETTING" />
        </dashboard-tile>

        <!-- Other wireless and network controls -->
        <dashboard-tile
                android:id="@+id/wireless_settings"
                android:title="@string/radio_controls_title"
                android:fragment="com.android.settings.WirelessSettings"
                android:icon="@drawable/ic_settings_more"
                />

    </dashboard-category>

    <!-- DEVICE -->
    <dashboard-category
            android:id="@+id/device_section"
            android:title="@string/header_category_device" >

        <!-- Home -->
        <dashboard-tile
                android:id="@+id/home_settings"
                android:title="@string/home_settings"
                android:fragment="com.android.settings.HomeSettings"
                android:icon="@drawable/ic_settings_home"
                />

        <!-- Display -->
        <dashboard-tile
                android:id="@+id/display_settings"
                android:title="@string/display_settings"
                android:fragment="com.android.settings.DisplaySettings"
                android:icon="@drawable/ic_settings_display"
                />

        <!-- Notifications -->
        <dashboard-tile
                android:id="@+id/notification_settings"
                android:title="@string/notification_settings"
                android:fragment="com.android.settings.notification.NotificationSettings"
                android:icon="@drawable/ic_settings_notifications"
                />

        <!-- Storage -->
        <dashboard-tile
                android:id="@+id/storage_settings"
                android:title="@string/storage_settings"
                android:fragment="com.android.settings.deviceinfo.Memory"
                android:icon="@drawable/ic_settings_storage"
                />

        <!-- Battery -->
        <dashboard-tile
                android:id="@+id/battery_settings"
                android:title="@string/power_usage_summary_title"
                android:fragment="com.android.settings.fuelgauge.PowerUsageSummary"
                android:icon="@drawable/ic_settings_battery"
                />

        <!-- Application Settings -->
        <dashboard-tile
                android:id="@+id/application_settings"
                android:title="@string/applications_settings"
                android:fragment="com.android.settings.applications.ManageApplications"
                android:icon="@drawable/ic_settings_applications"
                />

        <!-- Manage users -->
        <dashboard-tile
                android:id="@+id/user_settings"
                android:title="@string/user_settings_title"
                android:fragment="com.android.settings.users.UserSettings"
                android:icon="@drawable/ic_settings_multiuser"
                />

        <!-- Manage NFC payment apps -->
        <dashboard-tile
                android:id="@+id/nfc_payment_settings"
                android:title="@string/nfc_payment_settings_title"
                android:fragment="com.android.settings.nfc.PaymentSettings"
                android:icon="@drawable/ic_settings_nfc_payment"
                />

        <!-- Manufacturer hook -->
        <dashboard-tile
                android:id="@+id/manufacturer_settings"
                android:fragment="com.android.settings.WirelessSettings">
            <intent android:action="com.android.settings.MANUFACTURER_APPLICATION_SETTING" />
        </dashboard-tile>

    </dashboard-category>
每个dashboard-tile就是一个preference,点击后就会转到对应的fragment。


总结就是:activity先加载一个空的layout,其中有FrameLayout,然后将一个fragment放进去,在fragment中也是先加载了一个仅有一个LinearLayout的layout,接着在这个LinearLayout中加载转化的对象,形成设置的初始界面,如下图:


 






猜你喜欢

转载自blog.csdn.net/ywlyg/article/details/49836515