Android5.1 原生应用设置(Settings)主界面启动流程
2015-10-13 11:08
411 查看
别小看Android系统的设置程序,原生的Settings程序居然有10万行代码量,快赶上Kernel V1.0版本的代码量了,之所以这么多代码主要就是设置的功能点非常多非常杂,有的模块也很复杂,有的直接跟整个framework机制或流程有关,所以导致某些bug变成了重量级的问题,难以一时半会看出端倪,需要花费一定的时间去跟踪,比如跟踪系统的语言切换,当初这个bug我也是跟了16个小时,发现要从正面出击解决问题的可能性太小,后来在板型的overlay目录中进行一个覆盖配置,问题得到解决。
废话不多说,直接看代码吧,拿到一个app,肯定是从AndroidManifest.xml入手,因为这里会登记app要求的权限,Receiver监听,Activity或者Service等等,其中写明有android.intent.category.DEFAULT和android.intent.category.LAUNCHER的Activity就是app的入口Activity:
99 android:taskAffinity="com.android.settings"
100 android:label="@string/settings_label_launcher"
101 android:launchMode="singleTask"
102 android:targetActivity="Settings">
103 <intent-filter>
104 <action android:name="android.intent.action.MAIN" />
105 <category android:name="android.intent.category.DEFAULT" />
106 <category android:name="android.intent.category.LAUNCHER" />
107 </intent-filter>
108 </activity-alias>
这里才是真正的入口:
85 <activity android:name="Settings"
86 android:taskAffinity="com.android.settings"
87 android:label="@string/settings_label_launcher"
88 android:launchMode="singleTask">
89 <intent-filter>
90 <action android:name="android.settings.SETTINGS" />
91 <category android:name="android.intent.category.DEFAULT" />
92 </intent-filter>
93 <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
94 android:value="true" />
95 </activity>
2,./packages/apps/Settings/src/com/android/settings/Settings.java
24 public class Settings extendsSettingsActivity { //继承自SettingsActivity
3,./packages/apps/Settings/src/com/android/settings/SettingsActivity.java
489 @Override
490 protected voidonCreate(Bundle savedState) {
491 super.onCreate(savedState);
563 if (!mIsShowingDashboard) {
564 // Search is shown we are launched
15576
thru a Settings "shortcut". UPwill be shown
565 // only if it is a sub settings
566 if (mIsShortcut) {
567 mDisplayHomeAsUpEnabled = isSubSettings;
568 mDisplaySearch = false;
569 } else if (isSubSettings) {
570 mDisplayHomeAsUpEnabled = true;
571 mDisplaySearch = true;
572 } else {
573 mDisplayHomeAsUpEnabled = false;
574 mDisplaySearch = false;
575 }
576 setTitleFromIntent(intent);
577
578 Bundle initialArguments =intent.getBundleExtra(
EXTRA_SHOW_FRAGMENT_ARGUMENTS);
579 switchToFragment(initialFragmentName, initialArguments, true, false,
580 mInitialTitleResId, mInitialTitle, false);
581 } else {
582 // No UP affordance if we are displaying the main Dashboard
583 mDisplayHomeAsUpEnabled = false;
584 // Show Search affordance
585 mDisplaySearch = true;
586 mInitialTitleResId = R.string.dashboard_title;
587 switchToFragment(DashboardSummary.class.getName(),
null, false,false,
588 mInitialTitleResId, mInitialTitle, false);
589 }
948 private Fragment switchToFragment(StringfragmentName, Bundle args,
boolean validate, boolean addToBackStack, int titleResId,
CharSequence title, boolean withTransition) {
//利用反射机制实例化DashboardSummary
954 Fragment f = Fragment.instantiate(this,fragmentName, args);
955 FragmentTransaction transaction =getFragmentManager().beginTransaction();
956 transaction.replace(R.id.main_content,f);
。。。
}
R.layout.dashboard是设置的主界面的布局文件,也是设置其他子界面的入口:
4,./packages/apps/Settings/src/com/android/settings/dashboard/DashboardSummary.java
89 public View onCreateView(LayoutInflaterinflater, ViewGroup container,
90 Bundle savedInstanceState) {
92 mLayoutInflater = inflater;
94 final View rootView = inflater.inflate(R.layout.dashboard, container,false);
95 mDashboard = (ViewGroup) rootView.findViewById(R.id.dashboard_container);
97 return rootView;
98 }
68 public voidonResume(){
69 super.onResume();
71 sendRebuildUI();
。。。
}
169 private void sendRebuildUI() {
170 if(!mHandler.hasMessages(MSG_REBUILD_UI)) {
171 mHandler.sendEmptyMessage(MSG_REBUILD_UI);
172 }
173 }
46 private static final int MSG_REBUILD_UI = 1;
47 private Handler mHandler = new Handler() {
49 public void handleMessage(Message msg) {
50 switch (msg.what) {
51 case MSG_REBUILD_UI: {
52 final Context context = getActivity();
53 rebuildUI(context);
54 } break;
55 }
56 }
57 };
100 private void rebuildUI(Context context) {
106 long start = System.currentTimeMillis();
107 final Resources res = getResources();
108 mDashboard.removeAllViews();
111 List<DashboardCategory> categories = //categories就拥有设置主界面的完整信息
112 ((SettingsActivity) context).getDashboardCategories(true);
//先从R.layout.dashboard_category中找到textview并设置title;
//再找到其中的viewgroup,并用第二层循环实例化categories(i).tilesCount个//DashboardTileView并添加进去
116 for (int n = 0; n < count; n++) {
117 DashboardCategory category =categories.get(n);
119 View categoryView =mLayoutInflater.inflate(
R.layout.dashboard_category,mDashboard, false);
122 TextView categoryLabel = (TextView)categoryView.findViewById(R.id.category_title);
123 categoryLabel.setText(category.getTitle(res));
125 ViewGroup categoryContent =
126 (ViewGroup)categoryView.findViewById(R.id.category_content);
127 finalint tilesCount = category.getTilesCount();
129 for (int i = 0; i < tilesCount; i++) {
130 DashboardTile tile =category.getTile(i);
132 DashboardTileView tileView = newDashboardTileView(context);
133 updateTileView(context, res, tile,tileView.getImageView(),
134 tileView.getTitleTextView(), tileView.getStatusTextView());
136 tileView.setTile(tile);
138 categoryContent.addView(tileView);
139 }
142 mDashboard.addView(categoryView);
}
4.1,./packages/apps/Settings/src/com/android/settings/SettingsActivity.java
384 public List<DashboardCategory> getDashboardCategories(booleanforceRefresh) {
385 if (forceRefresh || mCategories.size() == 0) {
386 buildDashboardCategories(mCategories);
387 }
388 return mCategories;
389 }
978 private void buildDashboardCategories(List<DashboardCategory> categories){
979 categories.clear();
//dashboard_categories.xml包含的category有无线和网络,设备,个人和系统;
//每个category存储的信息包括title,fragment和icon
980 loadCategoriesFromResource(R.xml.dashboard_categories,categories);
//删除过时不用的设置项,比如sim卡设置项,代码太长直接看文件
981 updateTilesList(categories);
982 }
4.2,./packages/apps/Settings/src/com/android/settings/dashboard/DashboardTileView.java
47 public DashboardTileView(Context context, AttributeSet attrs) {
48 super(context, attrs);
50 final View view = LayoutInflater.from(context).inflate(R.layout.dashboard_tile,this);
52 mImageView = (ImageView) view.findViewById(R.id.icon);
53 mTitleTextView = (TextView) view.findViewById(R.id.title);
54 mStatusTextView = (TextView) view.findViewById(R.id.status);
55 mDivider = view.findViewById(R.id.tile_divider);
57 setOnClickListener(this);
58 setBackgroundResource(R.drawable.dashboard_tile_background);
59 setFocusable(true);
60 }
4.3,./packages/apps/Settings/src/com/android/settings/dashboard/DashboardSummary.java
148 private void updateTileView(Context context, Resources res,DashboardTile tile,
149 ImageView tileIcon, TextViewtileTextView, TextView statusTextView) {
151 if (tile.iconRes > 0) {
152 tileIcon.setImageResource(tile.iconRes);
153 } else {
154 tileIcon.setImageDrawable(null);
155 tileIcon.setBackground(null);
156 }
157
158 tileTextView.setText(tile.getTitle(res));
159
160 CharSequence summary = tile.getSummary(res);
161 if (!TextUtils.isEmpty(summary)) {
162 statusTextView.setVisibility(View.VISIBLE);
163 statusTextView.setText(summary);
164 } else {
165 statusTextView.setVisibility(View.GONE);
166 }
167 }
废话不多说,直接看代码吧,拿到一个app,肯定是从AndroidManifest.xml入手,因为这里会登记app要求的权限,Receiver监听,Activity或者Service等等,其中写明有android.intent.category.DEFAULT和android.intent.category.LAUNCHER的Activity就是app的入口Activity:
1,./packages/apps/Settings/AndroidManifest.xml
98 <activity-aliasandroid:name="Settings"99 android:taskAffinity="com.android.settings"
100 android:label="@string/settings_label_launcher"
101 android:launchMode="singleTask"
102 android:targetActivity="Settings">
103 <intent-filter>
104 <action android:name="android.intent.action.MAIN" />
105 <category android:name="android.intent.category.DEFAULT" />
106 <category android:name="android.intent.category.LAUNCHER" />
107 </intent-filter>
108 </activity-alias>
这里才是真正的入口:
85 <activity android:name="Settings"
86 android:taskAffinity="com.android.settings"
87 android:label="@string/settings_label_launcher"
88 android:launchMode="singleTask">
89 <intent-filter>
90 <action android:name="android.settings.SETTINGS" />
91 <category android:name="android.intent.category.DEFAULT" />
92 </intent-filter>
93 <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
94 android:value="true" />
95 </activity>
2,./packages/apps/Settings/src/com/android/settings/Settings.java
24 public class Settings extendsSettingsActivity { //继承自SettingsActivity
3,./packages/apps/Settings/src/com/android/settings/SettingsActivity.java
489 @Override
490 protected voidonCreate(Bundle savedState) {
491 super.onCreate(savedState);
563 if (!mIsShowingDashboard) {
564 // Search is shown we are launched
15576
thru a Settings "shortcut". UPwill be shown
565 // only if it is a sub settings
566 if (mIsShortcut) {
567 mDisplayHomeAsUpEnabled = isSubSettings;
568 mDisplaySearch = false;
569 } else if (isSubSettings) {
570 mDisplayHomeAsUpEnabled = true;
571 mDisplaySearch = true;
572 } else {
573 mDisplayHomeAsUpEnabled = false;
574 mDisplaySearch = false;
575 }
576 setTitleFromIntent(intent);
577
578 Bundle initialArguments =intent.getBundleExtra(
EXTRA_SHOW_FRAGMENT_ARGUMENTS);
579 switchToFragment(initialFragmentName, initialArguments, true, false,
580 mInitialTitleResId, mInitialTitle, false);
581 } else {
582 // No UP affordance if we are displaying the main Dashboard
583 mDisplayHomeAsUpEnabled = false;
584 // Show Search affordance
585 mDisplaySearch = true;
586 mInitialTitleResId = R.string.dashboard_title;
587 switchToFragment(DashboardSummary.class.getName(),
null, false,false,
588 mInitialTitleResId, mInitialTitle, false);
589 }
948 private Fragment switchToFragment(StringfragmentName, Bundle args,
boolean validate, boolean addToBackStack, int titleResId,
CharSequence title, boolean withTransition) {
//利用反射机制实例化DashboardSummary
954 Fragment f = Fragment.instantiate(this,fragmentName, args);
955 FragmentTransaction transaction =getFragmentManager().beginTransaction();
956 transaction.replace(R.id.main_content,f);
。。。
}
R.layout.dashboard是设置的主界面的布局文件,也是设置其他子界面的入口:
4,./packages/apps/Settings/src/com/android/settings/dashboard/DashboardSummary.java
89 public View onCreateView(LayoutInflaterinflater, ViewGroup container,
90 Bundle savedInstanceState) {
92 mLayoutInflater = inflater;
94 final View rootView = inflater.inflate(R.layout.dashboard, container,false);
95 mDashboard = (ViewGroup) rootView.findViewById(R.id.dashboard_container);
97 return rootView;
98 }
68 public voidonResume(){
69 super.onResume();
71 sendRebuildUI();
。。。
}
169 private void sendRebuildUI() {
170 if(!mHandler.hasMessages(MSG_REBUILD_UI)) {
171 mHandler.sendEmptyMessage(MSG_REBUILD_UI);
172 }
173 }
46 private static final int MSG_REBUILD_UI = 1;
47 private Handler mHandler = new Handler() {
49 public void handleMessage(Message msg) {
50 switch (msg.what) {
51 case MSG_REBUILD_UI: {
52 final Context context = getActivity();
53 rebuildUI(context);
54 } break;
55 }
56 }
57 };
100 private void rebuildUI(Context context) {
106 long start = System.currentTimeMillis();
107 final Resources res = getResources();
108 mDashboard.removeAllViews();
111 List<DashboardCategory> categories = //categories就拥有设置主界面的完整信息
112 ((SettingsActivity) context).getDashboardCategories(true);
//先从R.layout.dashboard_category中找到textview并设置title;
//再找到其中的viewgroup,并用第二层循环实例化categories(i).tilesCount个//DashboardTileView并添加进去
116 for (int n = 0; n < count; n++) {
117 DashboardCategory category =categories.get(n);
119 View categoryView =mLayoutInflater.inflate(
R.layout.dashboard_category,mDashboard, false);
122 TextView categoryLabel = (TextView)categoryView.findViewById(R.id.category_title);
123 categoryLabel.setText(category.getTitle(res));
125 ViewGroup categoryContent =
126 (ViewGroup)categoryView.findViewById(R.id.category_content);
127 finalint tilesCount = category.getTilesCount();
129 for (int i = 0; i < tilesCount; i++) {
130 DashboardTile tile =category.getTile(i);
132 DashboardTileView tileView = newDashboardTileView(context);
133 updateTileView(context, res, tile,tileView.getImageView(),
134 tileView.getTitleTextView(), tileView.getStatusTextView());
136 tileView.setTile(tile);
138 categoryContent.addView(tileView);
139 }
142 mDashboard.addView(categoryView);
}
4.1,./packages/apps/Settings/src/com/android/settings/SettingsActivity.java
384 public List<DashboardCategory> getDashboardCategories(booleanforceRefresh) {
385 if (forceRefresh || mCategories.size() == 0) {
386 buildDashboardCategories(mCategories);
387 }
388 return mCategories;
389 }
978 private void buildDashboardCategories(List<DashboardCategory> categories){
979 categories.clear();
//dashboard_categories.xml包含的category有无线和网络,设备,个人和系统;
//每个category存储的信息包括title,fragment和icon
980 loadCategoriesFromResource(R.xml.dashboard_categories,categories);
//删除过时不用的设置项,比如sim卡设置项,代码太长直接看文件
981 updateTilesList(categories);
982 }
4.2,./packages/apps/Settings/src/com/android/settings/dashboard/DashboardTileView.java
47 public DashboardTileView(Context context, AttributeSet attrs) {
48 super(context, attrs);
50 final View view = LayoutInflater.from(context).inflate(R.layout.dashboard_tile,this);
52 mImageView = (ImageView) view.findViewById(R.id.icon);
53 mTitleTextView = (TextView) view.findViewById(R.id.title);
54 mStatusTextView = (TextView) view.findViewById(R.id.status);
55 mDivider = view.findViewById(R.id.tile_divider);
57 setOnClickListener(this);
58 setBackgroundResource(R.drawable.dashboard_tile_background);
59 setFocusable(true);
60 }
4.3,./packages/apps/Settings/src/com/android/settings/dashboard/DashboardSummary.java
148 private void updateTileView(Context context, Resources res,DashboardTile tile,
149 ImageView tileIcon, TextViewtileTextView, TextView statusTextView) {
151 if (tile.iconRes > 0) {
152 tileIcon.setImageResource(tile.iconRes);
153 } else {
154 tileIcon.setImageDrawable(null);
155 tileIcon.setBackground(null);
156 }
157
158 tileTextView.setText(tile.getTitle(res));
159
160 CharSequence summary = tile.getSummary(res);
161 if (!TextUtils.isEmpty(summary)) {
162 statusTextView.setVisibility(View.VISIBLE);
163 statusTextView.setText(summary);
164 } else {
165 statusTextView.setVisibility(View.GONE);
166 }
167 }
相关文章推荐
- 解决vc中unable to connect to the MKS:Internal error问题
- 网络防火墙的设置技巧
- 不限连接数如何设置?
- 网络防火墙的设置
- 通过批处理bat设置系统环境变量的实现代码
- 如何设置域名接口
- js 提交和设置表单的值
- asp.net 设置GridView的选中行
- JS调用打印方法设置页眉页脚的实例
- jQuery使用attr()方法同时设置多个属性值用法实例
- Android 情景模式的设置代码
- 使用js 设置url参数
- Oracle中serveroutput参数一次设置永久保存方法
- php header函数的常用http头设置
- win2003 iis 404 设置方法与小技巧
- 远程分析IIS设置
- MongoDB为用户设置访问权限
- IIS6.0的默认权限和用户权限设置小结
- Java并发编程示例(二):获取和设置线程信息
- C#设置开机启动项、取消开机启动项