您的位置:首页 > 移动开发 > Android开发

Android5.0 Lollipop Setting启动分析

2015-11-14 16:57 435 查看
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中加载转化的对象,形成设置的初始界面,如下图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: