Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 淺談Android Settings模塊架構(1)

淺談Android Settings模塊架構(1)

編輯:關於Android編程

概述

Android Settings模塊說簡單也簡單,說難也難,裡面涉及到的知識點也挺多的。

我們知道Settings主要是用於配置一些系統選項或屬性值,通過修改設置項就能達到修改系統配置的作用。

那麼問題來了,Settings是如何實現修改後能改變系統配置的呢?Settings又是采用怎樣的架構實現的呢?裡面又涉及到哪些知識點呢?

讓我們一起來揭開她的神秘面紗吧!

原理分析

Settings的主要功能就是改變系統配置,那麼他是如何做到的呢?
  • Settings的戰友SettingsProvider
    通過跟蹤Settings源碼發現,Settings並不是孤軍作戰,它還有一個戰友 - SettingsProvider。
    
    SettingsProvider又是做什麼的呢?其實看到這個名字我們不難猜到他扮演著什麼樣的角色。
    
    SettingsProvider繼承ContentProvider,ContentProvider在android中主要扮演著數據共享的角色。
    
    SettingsProvider中有一個數據庫,並且這個數據庫是對外公開的。
    
    Settings與SettingsProvider之間又是什麼關系呢?且看下面分析。
    
    • Settings和SettingsProvider之間的關系
      Settings源碼位置:
        packages/apps/Settings/
      
      SettingsProvider源碼位置:
        frameworks/base/packages/SettingsProvider/
        frameworks/base/core/java/android/provider/Settings.java
      
      db在數據庫中存在的位置:
        /data/data/com.android.providers.settings/databases/settings.db
      
      他們之間存在什麼聯系呢?
      
      其實,Settings會對SettingsProvider中的數據庫進行操作和監聽。
      
      Settings中大部分選項都會涉及到對SettingsProvider的操作。
      
      • 原理分析
        通過跟蹤代碼發現,Settings大部分操作的就是SettingsProvider中的數據,也有一些直接操作系統屬性的等等。
        
        當用戶在修改系統設置時,大部分實際上是在修改SettingsProvider中的值。
        
        當SettingsProvider數據庫中的值被改變時,一些系統服務什麼的就會監聽到,這時候就會通過jni等當時操作底層,從而達到系統屬性或配置改變的效果。
        
        
        Andriod FramewZ喎?/kf/ware/vc/vcmsgTW9kdWxlIE5vdGUgVXJsIDQuanBn" height="446" src="/uploadfile/Collfiles/20160331/2016033109034036.jpg" width="620" />
        

        架構分析

        Settings處在安卓的應用層,不同於市場上的app,Settings屬於系統app,也是一個比較特別的app。
        
        • Settings特點
          1.Settings頁面很多,但是Activity卻很少,基本上都是使用PreferenceFragment
          
          2.Settings中包含大量對provider的操作與監聽
          
          3.Settings UI基本上都是采用Preference來實現
          
          • Settings架構
            1.Settings主界面Activity使用的是Settings
            
            2.Settings子界面Activity基本上都是使用SubSettings
            
            3.Settings與SubSettings中都是空Activity,這裡的空Activity指的是沒有重寫7大生命周期方法
            
            4.Settings與SubSettings都是繼承於SettingsActivity
            
            5.主界面使用的layout是:settings_main_dashboard,子界面使用的layout是:settings_main_prefs
            
            6.主界面settings_main_dashboard中是使用DashboardSummary(Fragment)進行填充,子界面都是使用各自的Fragment進行填充
            
            7.子界面fragment基本上都是直接或間接繼承SettingsPreferenceFragment
            
            8.主界面選項列表是定義在dashboard_categories.xml中,此文件是在SettingsActivity的buildDashboardCategories方法中進行解析的
            
            9.在Settings類中定義了很多static class,這些類都是繼承SettingsActivity,但都是空的,如BluetoothSettingsActivity
              這些類主要用於對外提供跳轉頁面,比如從SystemUI跳轉至Settings中的某個界面
            
            10.Settings類中定義了的static class被定義在AndroidManifest中,通過meta-data參數將對應的Fragment綁定在一起
            
            11.在Activity中填充Fragment主要使用的是SettingsActivity中的switchToFragment方法
            
            • settings_main_dashboard中只有一個FrameLayout,後面會將其替換為DashboardSummary
              
              
              <framelayout android:background="@color/dashboard_background_color" android:id="@+id/main_content" android:layout_height="match_parent" android:layout_width="match_parent" xmlns:android="http://schemas.android.com/apk/res/android" />
              • settings_main_prefs中也存在一個叫main_content的FrameLayout,後面會將其替換為各自的Fragment,switch_bar與button_bar只有在某些頁面才會顯示
                
                
                   <framelayout android:background="?attr/preferenceBackgroundColor" android:id="@+id/main_content" android:layout_height="match_parent" android:layout_width="match_parent" />   
                
                
                
                
                • Settings主界面結構
                  
                  Andriod Framework Module Note Url 5 5.jpg
                  
                  1.從圖中可以看到,紅色框中的屬於一個DashboardCategory,藍色框中的屬於DashboardTileView
                  2.在DashboardSummary中有多個DashboardCategory,DashboardCategory中包含一個title和多個DashboardTileView
                  3.DashboardTileView具有onClick方法,點擊後啟動子界面,使用的是Utils.startWithFragment進行跳轉
                  4.startWithFragment方法中將子界面的Fragment傳遞給activity,這裡會綁定對應的activity,也就是SubSettings
                  

                  Utils.startWithFragment關鍵方法

                     
                  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; }

                  SettingsActivity.onCreate方法中的關鍵代碼

                  
                  
                  @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.當點擊主界面上的item時會調用Utils.startWithFragment方法
                  2.在Utils.startWithFragment會跳轉至SubSettings,對應的fragment也作為參數傳遞給了SubSettings
                  3.SubSettings是一個空的activity,但SubSettings繼承於SettingsActivity,因此會調用父類SettingsActivity的onCreate方法
                  4.在onCreate方法中,className為SubSettings,isSubSettings為true,mIsShowingDashboard為false
                  5.因此會執行switchToFragment(initialFragmentName, initialArguments, true, false, mInitialTitleResId, mInitialTitle, false);
                  6.通過switchToFragment將settings_main_prefs的main_content替換為了子界面對應的fragment
                  

                  簡單類圖

                  從下面類圖中可以看出

                  1.Settings中主要的Activity為SettingsActivity,其他基本上都是繼承該activity,並且其他基本上都是空的
                  2.Settings中fragment基本上都是繼承至SettingsPreferenceFragment
                  
                  
                  Andriod Framework Module Note Url 1.jpg
                  
                  
                  Andriod Framework Module Note Url 2.jpg
                  

                  時序圖

                  下面的時序圖為點擊Settings圖標啟動Settings,在點擊item啟動子界面的時序圖
                  
                  從圖中可以看出啟動的一個流程,按照這個流程,幾乎所有的界面都會執行SettingsActivity
                  
                  
                  Andriod Framework Module Note Url 3.jpg
                   
                  
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved