別小看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:
1,./packages/apps/Settings/AndroidManifest.xml
98
99 android:taskAffinity="com.android.settings"
100 android:label="@string/settings_label_launcher"
101 android:launchMode="singleTask"
102 android:targetActivity="Settings">
103
104
105
106
107
108
這里才是真正的入口:
85
86 android:taskAffinity="com.android.settings"
87 android:label="@string/settings_label_launcher"
88 android:launchMode="singleTask">
89
90
91
92
93
94 android:value="true" />
95
2,./packages/apps/Settings/src/com/android/settings/Settings.java
24public 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 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
89public View onCreateView(LayoutInflaterinflater, ViewGroup container,
90Bundle savedInstanceState) {
92mLayoutInflater = inflater;
94final View rootView = inflater.inflate(R.layout.dashboard, container,false);
95mDashboard = (ViewGroup) rootView.findViewById(R.id.dashboard_container);
97return 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 categories =//categories就擁有設置主界面的完整信息
112 ((SettingsActivity) context).getDashboardCategories(true);
//先從R.layout.dashboard_category中找到textview並設置title;
//再找到其中的viewgroup,並用第二層循環實例化categories(i).tilesCount個//DashboardTileView並添加進去
116for (int n = 0; n < count; n++) {
117DashboardCategory category =categories.get(n);
119View categoryView =mLayoutInflater.inflate(
R.layout.dashboard_category,mDashboard,false);
122TextView categoryLabel = (TextView)categoryView.findViewById(R.id.category_title);
123categoryLabel.setText(category.getTitle(res));
125ViewGroup categoryContent =
126(ViewGroup)categoryView.findViewById(R.id.category_content);
127finalint tilesCount = category.getTilesCount();
129for (int i = 0; i < tilesCount; i++) {
130DashboardTile tile =category.getTile(i);
132DashboardTileView tileView = newDashboardTileView(context);
133updateTileView(context, res, tile,tileView.getImageView(),
134tileView.getTitleTextView(), tileView.getStatusTextView());
136tileView.setTile(tile);
138categoryContent.addView(tileView);
139}
142mDashboard.addView(categoryView);
}
4.1,./packages/apps/Settings/src/com/android/settings/SettingsActivity.java
384 public List getDashboardCategories(booleanforceRefresh) {
385 if (forceRefresh || mCategories.size() == 0) {
386 buildDashboardCategories(mCategories);
387 }
388 return mCategories;
389 }
978 private void buildDashboardCategories(List 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
47public DashboardTileView(Context context, AttributeSet attrs) {
48super(context, attrs);
50final View view = LayoutInflater.from(context).inflate(R.layout.dashboard_tile,this);
52mImageView = (ImageView) view.findViewById(R.id.icon);
53mTitleTextView = (TextView) view.findViewById(R.id.title);
54mStatusTextView = (TextView) view.findViewById(R.id.status);
55mDivider = view.findViewById(R.id.tile_divider);
57setOnClickListener(this);
58setBackgroundResource(R.drawable.dashboard_tile_background);
59setFocusable(true);
60}
4.3,./packages/apps/Settings/src/com/android/settings/dashboard/DashboardSummary.java
148private void updateTileView(Context context, Resources res,DashboardTile tile,
149ImageView tileIcon, TextViewtileTextView, TextView statusTextView) {
151if (tile.iconRes > 0) {
152tileIcon.setImageResource(tile.iconRes);
153} else {
154tileIcon.setImageDrawable(null);
155tileIcon.setBackground(null);
156}
157
158tileTextView.setText(tile.getTitle(res));
159
160CharSequence summary = tile.getSummary(res);
161if (!TextUtils.isEmpty(summary)) {
162statusTextView.setVisibility(View.VISIBLE);
163statusTextView.setText(summary);
164} else {
165statusTextView.setVisibility(View.GONE);
166}
167}