Principle analysis
The main function of Settings is to change the system configuration, so how does he do it?
Settings comrades SettingsProvider
By tracking the Settings source code, Settings is not alone, it also has a comrade - SettingsProvider.
What does the SettingsProvider do? In fact, it is not difficult to guess what role he plays when he sees this name.
The SettingsProvider inherits the ContentProvider, and the ContentProvider plays a role of data sharing in android.
There is a database in the SettingsProvider, and this database is publicly available.
What is the relationship between Settings and SettingsProvider? And look at the analysis below.
Relationship between Settings and SettingsProvider
Settings source location:
Packages/apps/Settings/
SettingsProvider source location:
Frameworks/base/packages/SettingsProvider/
Frameworks/base/core/java/android/provider/Settings.java
The location of db in the database:
/data/data/com.android.providers.settings/databases/settings.db
What is the connection between them?
In fact, Settings will operate and listen to the database in the SettingsProvider.
Most of the options in Settings will involve the operation of the SettingsProvider.
Principle analysis
Through the tracking code, most of the operations of Settings are the data in the SettingsProvider, there are some direct operating system properties and so on.
When the user is modifying the system settings, most of them are actually modifying the values in the SettingsProvider.
When the value in the SettingsProvider database is changed, some system services will be monitored. At this time, the underlying operation will be performed by jni, etc., to achieve the effect of system properties or configuration changes.
technology sharing
Architecture analysis
Settings is in the Android application layer. Unlike the app on the market, Settings belongs to the system app and is also a special app.
Settings features
1.The Settings page is a lot, but the Activity is very few, basically using PreferenceFragment
2.Settings contains a lot of operations and listeners to the provider
3.Settings UI is basically implemented using Preference
Settings architecture
1.Settings main interface Activity is using Settings
2.Settings sub-interface Activity is basically using SubSettings
3.Settings and SubSettings are empty activities, the empty Activity here refers to no rewriting 7 major life cycle methods
4.Settings and SubSettings are both inherited from SettingsActivity
5. The layout used by the main interface is: settings_main_dashboard, and the layout used by the sub-interface is: settings_main_prefs
6. The main interface settings_main_dashboard is filled with DashboardSummary (Fragment), the sub-interfaces are filled with their own Fragment
7. The sub-interface fragment basically inherits the SettingsPreferenceFragment directly or indirectly.
8. The main interface option list is defined in the dashboard_categories.xml, this file is parsed in the buildDashboardCategories method of SettingsActivity
9. Define a lot of static classes in the Settings class, these classes are inherited from SettingsActivity, but are empty, such as BluetoothSettingsActivity
These classes are mainly used to provide jump pages to the outside world, such as jumping from SystemUI to an interface in Settings.
10. The static class defined in the Settings class is defined in the AndroidManifest, and the corresponding Fragment is bound together by the meta-data parameter.
11. Filling the Fragment in the Activity mainly uses the switchToFragment method in SettingsActivity
There is only one FrameLayout in settings_main_dashboard, which will be replaced by DashboardSummary later.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/dashboard_background_color" />
There is also a FrameLayout called main_content in settings_main_prefs, which will be replaced with its own Fragment. Switch_bar and button_bar will only be displayed on some pages.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1"
android:orientation="vertical" >
<com.android.settings.widget.SwitchBar
android:id="@+id/switch_bar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:background="@drawable/switchbar_background"
android:theme="?attr/switchBarTheme" />
<FrameLayout
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/preferenceBackgroundColor" />
</LinearLayout>
<RelativeLayout
android:id="@+id/button_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0"
android:visibility="gone" >
<Button
android:id="@+id/back_button"
android:layout_width="150dip"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_margin="5dip"
android:text="@*android:string/back_button_label" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:orientation="horizontal" >
<Button
android:id="@+id/skip_button"
android:layout_width="150dip"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="@*android:string/skip_button_label"
android:visibility="gone" />
<Button
android:id="@+id/next_button"
android:layout_width="150dip"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="@*android:string/next_button_label" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>
1. As you can see from the figure, the red box belongs to a DashboardCategory, and the blue box belongs to the DashboardTileView.
2. There are multiple DashboardCategory in DashboardSummary, DashboardCategory contains a title and multiple DashboardTileView
3. DashboardTileView has onClick method, click to launch the sub-interface, use Utils.startWithFragment to jump
4.startWithFragment method to pass the Fragment of the sub-interface to the activity, here will bind the corresponding activity, which is SubSettings
utils.startwithfragment Key method
public static void startWithFragment(Context context, String fragmentName, Bundle args,
Fragment resultTo, int resultRequestCode, int titleResId,
CharSequence title) {
startWithFragment(context, fragmentName, args, resultTo, resultRequestCode,
null /* titleResPackageName */, titleResId, title, false /* not a shortcut */);
}
public static void startWithFragment(Context context, String fragmentName, Bundle args,
Fragment resultTo, int resultRequestCode, String titleResPackageName, int titleResId,
CharSequence title, boolean isShortcut) {
Intent intent = onBuildStartFragmentIntent(context, fragmentName, args,
titleResPackageName,
titleResId, title, isShortcut);
if (resultTo == null) {
context.startActivity(intent);
} else {
resultTo.startActivityForResult(intent, resultRequestCode);
}
}
public static Intent onBuildStartFragmentIntent(Context context, String fragmentName,
Bundle args, String titleResPackageName, int titleResId, CharSequence title,
boolean isShortcut) {
Intent intent = new Intent(Intent.ACTION_MAIN);
if (BluetoothSettings.class.getName().equals(fragmentName)) {
intent.setClass(context, SubSettings.BluetoothSubSettings.class);
intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_AS_SUBSETTING, true);
} else if (WifiSettings.class.getName().equals(fragmentName)) {
intent.setClass(context, SubSettings.WifiSubSettings.class);
intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_AS_SUBSETTING, true);
} else {
intent.setClass(context, SubSettings.class);
}
intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, fragmentName);
intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RES_PACKAGE_NAME,
titleResPackageName);
intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RESID, titleResId);
intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE, title);
intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_AS_SHORTCUT, isShortcut);
return intent;
}
Key code in the SettingsActivity.onCreate method
@Override
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
// Should happen before any call to getIntent()
getMetaData();
final Intent intent = getIntent();
// Getting Intent properties can only be done after the super.onCreate(...)
final String initialFragmentName = intent.getStringExtra(EXTRA_SHOW_FRAGMENT);
mIsShortcut = isShortCutIntent(intent) || isLikeShortCutIntent(intent) ||
intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SHORTCUT, false);
final ComponentName cn = intent.getComponent();
final String className = cn.getClassName();
mIsShowingDashboard = className.equals(Settings.class.getName());
// This is a "Sub Settings" when:
// - this is a real SubSettings
// - or :settings:show_fragment_as_subsetting is passed to the Intent
final boolean isSubSettings = className.equals(SubSettings.class.getName()) ||
intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SUBSETTING, false);
setContentView(mIsShowingDashboard ?
R.layout.settings_main_dashboard : R.layout.settings_main_prefs);
mContent = (ViewGroup) findViewById(R.id.main_content);
getFragmentManager().addOnBackStackChangedListener(this);
if (savedState != null) {
......
} else {
if (!mIsShowingDashboard) {
......
setTitleFromIntent(intent);
Bundle initialArguments = intent.getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
switchToFragment(initialFragmentName, initialArguments, true, false,
mInitialTitleResId, mInitialTitle, false);
} else {
......
mInitialTitleResId = R.string.dashboard_title;
switchToFragment(DashboardSummary.class.getName(), null, false, false,
mInitialTitleResId, mInitialTitle, false);
}
}
......
}
1. When the item on the main interface is clicked, the Utils.startWithFragment method is called.
2. In Utils.startWithFragment will jump to SubSettings, the corresponding fragment is also passed as a parameter to SubSettings
3.SubSettings is an empty activity, but SubSettings inherits from SettingsActivity, so it will call the onCreate method of the parent class SettingsActivity.
4. In the onCreate method, className is SubSettings, isSubSettings is true, mIsShowingDashboard is false
5. Therefore, switchToFragment(initialFragmentName, initialArguments, true, false, mInitialTitleResId, mInitialTitle, false) will be executed;
6. Replace the main_content of settings_main_prefs with the fragment corresponding to the sub-interface by switchToFragment
Simple class Diagram
As you can see from the following class diagram
1. The main Activity in Settings is SettingsActivity, the other is basically inheriting the activity, and the other is basically empty.
2. The fragments in Settings are basically inherited to SettingsPreferenceFragment
Timing Diagram
The sequence diagram below launches settings for clicking on the Settings icon, clicking on the item Start sub-interface timing diagram
You can see a process that starts up, and according to this process, almost all of the interfaces will execute settingsactivity
Android Settings Module Architecture Analysis <1>