Androidシステムのソースコード解析(一)---Settings
12594 ワード
本文は博主のために苦労してまとめます.転載は出所を明記してください.http://blog.csdn.net/zrf1335348191/article/details/50837027
最近はAndroidのSettingsソースを研究しています.まずソースのカタログ構造を見てください.967ぐらいの書類は頭が痛くて手がつけられませんか?弁舌さわやかにしてください.
1,初めてSettingsを知った
まず、こんなに多くのファイルは、いったいどのファイルがメインインターフェースですか?Settingsディレクトリの下でAndroid manifest.xmlリストの設定ファイルを見つけて、まず起動するactivityを見つけます.
最近はAndroidのSettingsソースを研究しています.まずソースのカタログ構造を見てください.967ぐらいの書類は頭が痛くて手がつけられませんか?弁舌さわやかにしてください.
1,初めてSettingsを知った
まず、こんなに多くのファイルは、いったいどのファイルがメインインターフェースですか?Settingsディレクトリの下でAndroid manifest.xmlリストの設定ファイルを見つけて、まず起動するactivityを見つけます.
<activity android:name="Settings" android:label="@string/settings_label_launcher" android:taskAffinity="com.android.settings" android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.settings.SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
設定されたメインインターフェースはSettings.Javaであり、public class Settings extends PreferenceActivity
implements ButtonBarHandler, OnAccountsUpdateListener {
.....
<pre name="code" class="java"> loadHeadersFromResource(R.xml.settings_headers, headers);//
.....
}
所对应的xml文件为Settings_headers.xml(res\xml\)文件。在此摘列出xml文件的一部分。
各選択とクリックできるアイテムは基本的に四つの属性があります.headerを例にとる<preference-headers xmlns:android="http://schemas.android.com/apk/res/android"> <!-- WIRELESS and NETWORKS --> <header android:id="@+id/wireless_section" android:title="@string/header_category_wireless_networks" /> <!-- Wifi --> <header android:id="@+id/wifi_settings" android:fragment="com.android.settings.wifi.WifiSettings" android:title="@string/wifi_settings_title" android:icon="@drawable/ic_settings_wireless" /> <!-- MobileData --> <header android:id="@+id/mobiledata_settings" android:icon="@drawable/stat_notify_mobile_data" android:title="@string/data_usage_enable_mobile"> <intent android:action="android.intent.action.MAIN" android:targetPackage="com.android.phone" android:targetClass="com.android.phone.MobileNetworkSettings" /> </header> ......... </preference-headers>
id:対応のid
fragment:クリックした後のfragment:WifiSettings
title:headerのメインタイトル、つまりSettingsメインインターフェースに表示されるテキスト:WLAN
icon:headerのアイコン、つまりテキストの左側に表示されているアイコンです.
この2つのファイルを分析してSettingsのレイアウトをまとめることができます.SettingsのメインインターフェースはPreferenceActivityを介して、Preferenceは偏愛偏愛偏愛を意味しています.キーパッドを使って記録ユーザーの前回の選択を記録し、次回このインターフェースに入る時に直接最後の選択を読み取って配置する必要がないのが特徴です.Activityはインターフェースを意味し、preferenceactivityは両者を結合します.各行は一つのheaderに属し、listviewの中のitemに相当し、それぞれのheaderはfragmentに対応しています.fragmentのロードはActivityに依存しています.依存するActivityはSubSettings.javaです.Settingソースの分析は二つのステップに分けて入手できます./** *Stub class for showing sub-settings; we can't use the main Settings class * since for our app it is a special singleTask class. * Settings.java fragment, , singleTask */ public class SubSettings extends Settings { @Override public boolean onNavigateUp() { finish(); return true; } @Override protected boolean isValidFragment(String fragmentName) { return true; } }
最初に、headersリストの読み込み
第二に、headerのクリックイベントの処理
以上の二つの問題を解決したら、異なるモジュールの分析を開始できます.
2,インターフェースレイアウトを設定し、headersをロードする.
(1)xmlレイアウトファイルの読み込み
二種類の方法でxmlファイルレイアウトを読み込むことができます.
方法1:方法二:loadHeadersFromResource(R.xml.settings_headers, headers);
(2)アドホッターを定義してアドホックをロードして表示するaddPreferencesFromResource(R.xml.fragmented_preferences_inner);
インターフェースレイアウトを設定するアダプターadapperには、以下のタイプがあります.private static class HeaderAdapter extends ArrayAdapter<Header> {
i>,HEADER_TYPE_CATEGORY:ピントがないので、クリックしてはいけません.
ii>,HEADER_TYPE_BUTON:buttonを持つheader、buttonのvisibility(視認性)には条件があります.
iii>,HEADER_TYPE_NORMAL:正常にフォーカスを取得できます.クリックできるのはbuttonを持たないheaderです.
3、Settings.javaソース分析(部分抽出)
(1)onCreateの方法で:以上のコードはwindowsのuiをレイアウトするために使われます.つまり上部のステータスバーのレイアウトは、通常は変更されません.if (getIntent().hasExtra(EXTRA_UI_OPTIONS)) { getWindow().setUiOptions(getIntent().getIntExtra(EXTRA_UI_OPTIONS, 0)); }
このコードは認証を設定したり、口座情報を更新したりします.普通は変更しません.mAuthenticatorHelper = new AuthenticatorHelper(); mAuthenticatorHelper.updateAuthDescriptions(this); mAuthenticatorHelper.onAccountsUpdated(this, null);
表示方法のソースコードを見ることができます:メソッドは、配置ファイルAndroid manifest.xmlのgetMetaData();
ノードのデータを取得することです. private void getMetaData() { try { // Androidmanifest.xml <meta-data.../> ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(), PackageManager.GET_META_DATA); // , if (ai == null || ai.metaData == null) return; // header id mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID); // header fragment mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS); // Check if it has a parent specified and create a Header object // parent, , //parent title final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE); //parent fragment String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS); if (parentFragmentClass != null) { mParentHeader = new Header(); mParentHeader.fragment = parentFragmentClass; if (parentHeaderTitleRes != 0) { mParentHeader.title = getResources().getString(parentHeaderTitleRes); } } } catch (NameNotFoundException nnfe) { // No recovery } }
onIsMultiPane()はダブルスクリーンMultiPaneかどうかを判断し、フラットパネルのダブルスクリーン表示、携帯電話の一般的なシングルスクリーンのSinglePaneは表示するので、onIsMultiPane()方法はfalseに戻るように設定することができます.if (!onIsHidingHeaders() && onIsMultiPane()) { highlightHeader(mTopLevelHeaderId); // Force the title so that it doesn't get overridden by a direct launch of // a specific settings screen. setTitle(R.string.settings_label); }
onIsHdingHeadersは、両方のスクリーンのheadersが表示されているかどうかを判断します.
条件が満たされれば、highlight Header()の方法で他のheaderと区別し、ナビゲーションバーtitleを設定にし、上書きしないようにします.if (onIsMultiPane()) { // ,false getActionBar().setDisplayHomeAsUpEnabled(false); // ,false getActionBar().setHomeButtonEnabled(false); // getActionBar().setDisplayShowHomeEnabled(true) }
以上代码是说如果是多屏显示,则对导航栏左上角程序图标以及返回图标的设置
接下来是利用savedInstanceState恢复数据的操作,不再贴出
現在のheaderのタイトル表示を設定します.showBreadCrumbs(mCurrentHeader.title, null);
parentheaderのタイトルtitleとtitleを設定するクリックイベントを設定します.if (mParentHeader != null) { setParentTitle(mParentHeader.title, null, new OnClickListener() { @Override public void onClick(View v) { 。。。。。。 } }); }
(2)オンスレム方法は、すべてのheaderを示し、header Adapter.reume()方法によって表示される.
headerすなわちitemは、どのようなタイプのレイアウトを表示する必要がありますか?このadapperで変更することができます.異なるアイテムに対して異なるレイアウトファイルを設定します.(3)onBulildStartFrangentIntent方法private static class HeaderAdapter extends ArrayAdapter<Header> { static int getHeaderType(Header header) { ......... } public View getView(int position, View convertView, ViewGroup parent) { .......... } }
(4)onBuiildHeaders方法は、レイアウト、およびheadersを更新し、PreferenceActivityのoncreate()方法で呼び出され、さらにonGet Initial Header()方法もPreferenceActivityのoncreate方法で呼び出されます.@Override public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args, int titleRes, int shortTitleRes) { Intent intent = super.onBuildStartFragmentIntent(fragmentName, args, titleRes, shortTitleRes); // Some fragments want split ActionBar; these should stay in sync with // uiOptions for fragments also defined as activities in manifest. // header fragment window if (WifiSettings.class.getName().equals(fragmentName) || WifiP2pSettings.class.getName().equals(fragmentName) || BluetoothSettings.class.getName().equals(fragmentName) ||....) { // fragment activity, SubSettings intent.putExtra(EXTRA_UI_OPTIONS, ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW); } intent.setClass(this, SubSettings.class); return intent; }
@Override public void onBuildHeaders(List<Header> headers) { if (!onIsHidingHeaders()) { loadHeadersFromResource(R.xml.settings_headers, headers); // header , // header updateHeaderList(headers); } }
(5)doValidCheck(),以及isValidFragment 用来检查fragment是否有效,为适配Android4.4以下版本,保证不出异常
(6)onNewIntent:activity启动模式为singletask单任务模式,如果在战中存在activity的实例,当再次通过intent调起时不会再去oncreate创建实例,而是onNewIntent去重用该实例
(7)Settings.javaの中の内部類、Settings.javaの中に多くの実現の内部類があります.@Override public void onNewIntent(Intent intent) { super.onNewIntent(intent); // If it is not launched from history, then reset to top-level if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0) { if (mFirstHeader != null && !onIsHidingHeaders() && onIsMultiPane()) { switchToHeaderLocal(mFirstHeader); } getListView().setSelectionFromTop(0, 0); } }
これらの内部クラスは、fragmentをロードするために、fragmentの宿主として、Android manift.xmlから見ることができます.。。。。。。 public static class SecuritySettingsActivity extends Settings { /* empty */ } public static class LocationSettingsActivity extends Settings { /* empty */ } 。。。。。。。。
4、カスタム操作<activity android:name="Settings$WirelessSettingsActivity" android:taskAffinity="com.android.settings" android:label="@string/wireless_networks_settings_title" android:parentActivityName="Settings"> 。。。。。。 </activity>
Settingsインターフェースのレイアウト原理が分かりましたら、Settingsのメインインターフェースのレイアウトを勝手に添削できます.対応はheaderの修正です.
(1)headerを修正する:xmlファイルの下に修正したいheader対応のノード、テキスト、テキストの左側のアイコンを見つけ、入力したfragmentをクリックして修正すればいいです.
(2)headerを追加します.例えば「権限管理」を追加したいです.作り方は以下の通りです.
i>、Settings.headers.xmlファイルにheaderノードを追加します.ii>,新規fragment,AuthortyManagement Settings類<header android:id="@+id/authority_management android:fragment="com.android.settings.AuthorityManagementSettings" android:icon="@drawable/ic_settings_authority" android:title="@string/authority_settings"/>
public class DeviceInfoSettings extends RestrictedSettingsFragment { ........ @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); addPreferencesFromResource(R.xml.authority_management_settings); ......... } }