Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 5.1 Settings模塊源碼分析

Android 5.1 Settings模塊源碼分析

編輯:關於Android編程

前述:

本人已工作兩年多,但是依然感覺還是Android的門外漢,之前一直從事Android的應用開發,每天就是各種調用SDK方法,各種拷貝網上的源碼以及jar包,從來也不管為啥這樣用,由於換了一份工作才開始接觸到Android的源碼,感覺Android的水好深啊。

今天這篇博客也是我的處女作啊,以後也希望通過多多研究源碼來寫出更多的博客,我覺得寫博客主要還是作為一個記錄吧,不然感覺有的東西真的很容易丟,尤其是平時不怎麼接觸的模塊。

好啦,接下來開始今天的Setting旅行啦。

Settings簡述:

Setting模塊大家還是比較熟悉的吧?其實Setting也不是什麼高級的東西,它就是一個APP,屬於Android的應用層,源碼在packages\apps\Settings中,今天分析的源碼是基於Android5.1,如下圖是5.1Setting模塊的界面:

\

 

查看一個應用首先是查看這個應用的AndroidManifest.xml文件,以便查看程序的入口,Setting模塊的入口是Setting.java這個類,這個類繼承SettingActivity,但是沒有繼承任何的方法,但卻定義了一大堆內部類。

 

/**
 * Top-level Settings activity
 */
public class Settings extends SettingsActivity {
    public static class DateTimeSettingsActivity extends SettingsActivity { /* empty */ }
    public static class StorageSettingsActivity extends SettingsActivity { /* empty */ }
    public static class WifiSettingsActivity extends SettingsActivity { /* empty */ }
    public static class WifiP2pSettingsActivity extends SettingsActivity { /* empty */ }
    public static class InputMethodAndLanguageSettingsActivity extends SettingsActivity { /* empty */ }
    public static class KeyboardLayoutPickerActivity extends SettingsActivity { /* empty */ }
    public static class InputMethodAndSubtypeEnablerActivity extends SettingsActivity { /* empty */ }
    public static class VoiceInputSettingsActivity extends SettingsActivity { /* empty */ }
    public static class SpellCheckersSettingsActivity extends SettingsActivity { /* empty */ }
    public static class LocalePickerActivity extends SettingsActivity { /* empty */ }
    public static class UserDictionarySettingsActivity extends SettingsActivity { /* empty */ }
    public static class HomeSettingsActivity extends SettingsActivity { /* empty */ }
    public static class DisplaySettingsActivity extends SettingsActivity { /* empty */ }
    public static class DeviceInfoSettingsActivity extends SettingsActivity { /* empty */ }
    public static class ApplicationSettingsActivity extends SettingsActivity { /* empty */ }
    public static class ManageApplicationsActivity extends SettingsActivity { /* empty */ }
}



 

這些類都是Setting模塊的子界面類,是特定功能的類,比如WifiSettingsActivity是WiFi模塊相關的類。

所以接下來我們直接分析SettingActivity這個類就可以了。

 

SettingActivity.java:

先看該類的OnCreate方法

 

 @Override
    protected void onCreate(Bundle savedState) {
        super.onCreate(savedState);

        // Should happen before any call to getIntent()
        getMetaData();

        final Intent intent = getIntent();

 

先調用getMetaData()方法,用於加載一些元數據,進入getMetaData()方法

 

private void getMetaData() {
        try {
            ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
                    PackageManager.GET_META_DATA);
            if (ai == null || ai.metaData == null) return;
            mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
        } catch (NameNotFoundException nnfe) {
            // No recovery
            Log.d(LOG_TAG, "Cannot get Metadata for: " + getComponentName().toString());
        }
}

 

主要作用就是通過META_DATA_KEY_FRAGMENT_CLASS這個屬性獲得額外的mFragmentClass,如果可以獲得將啟動對應的mFragmentClass的Activity,但是直接啟動Setting不會獲得該數據。

 

繼續往下看代碼

 

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


 

由於我們是從Setting啟動的,所以mIsShowingDashboard的值為true,而isSubSettings的值是false。

 

 

setContentView(mIsShowingDashboard ?
R.layout.settings_main_dashboard : R.layout.settings_main_prefs);

 

由於mIsShowingDashboard的值為true,所以使用的是R.layout.settings_main_dashboard

 

<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"></framelayout>

 

同時繼續往下走,會看到這段代碼塊:

 

if (savedState != null) {
   ...         
} else {
    if (!mIsShowingDashboard) {
      ...
    } else {
	// No UP affordance if we are displaying the main Dashboard
	mDisplayHomeAsUpEnabled = false;
        // Show Search affordance
        mDisplaySearch = true;
        mInitialTitleResId = R.string.dashboard_title;
        switchToFragment(DashboardSummary.class.getName(), null, false, false,
        mInitialTitleResId, mInitialTitle, false);
    }
}

這裡由於是第一次啟動,所以savedState 為null,同時mIsShowingDashboard的值為true,看到進入了switchToFragment這個方法,這裡准備切換到DashboardSummary這個Fragment。

 

DashboardSummary.java

DashboardSummary的onCreateView方法加載了R.layout.dashboard,代碼如下:

 

 



        

 

 

接下來將是重點,開始真正加載Setting的界面了,在OnResume方法中最終會調用rebuildUI()方法,該方法源碼:

 

 

private void rebuildUI(Context context) {
        if (!isAdded()) {
            Log.w(LOG_TAG, "Cannot build the DashboardSummary UI yet as the Fragment is not added");
            return;
        }

        long start = System.currentTimeMillis();
        final Resources res = getResources();
//mDashboard這個View就是整個界面的總View
        mDashboard.removeAllViews();
(1)這裡調用SettingActivity的getDashboardCategories,也就是加載整個Setting的內容
        List categories =
                ((SettingsActivity) context).getDashboardCategories(true);

        final int count = categories.size();

        for (int n = 0; n < count; n++) {
            DashboardCategory category = categories.get(n);

            View categoryView = mLayoutInflater.inflate(R.layout.dashboard_category, mDashboard,
                    false);

            TextView categoryLabel = (TextView) categoryView.findViewById(R.id.category_title);
            categoryLabel.setText(category.getTitle(res));

            ViewGroup categoryContent =
                    (ViewGroup) categoryView.findViewById(R.id.category_content);

            final int tilesCount = category.getTilesCount();
            for (int i = 0; i < tilesCount; i++) {
                DashboardTile tile = category.getTile(i);
//(2)創建DashboardTileView,也就是每個Setting的內容
                DashboardTileView tileView = new DashboardTileView(context);
                updateTileView(context, res, tile, tileView.getImageView(),
                        tileView.getTitleTextView(), tileView.getStatusTextView());

                tileView.setTile(tile);

                categoryContent.addView(tileView);
            }

            // Add the category
            mDashboard.addView(categoryView);
        }
        long delta = System.currentTimeMillis() - start;
        Log.d(LOG_TAG, "rebuildUI took: " + delta + " ms");
}


 

接下來將對上面代碼標注的序號處進行說明:

 

(1)處最終會調用SettingActivity的buildDashboardCategories方法,

 

 

private void buildDashboardCategories(List categories) {
        categories.clear();
        loadCategoriesFromResource(R.xml.dashboard_categories, categories);
        updateTilesList(categories);
}

該方法將加載一個xml文檔並使用Android默認的xml解析器XmlPullParser對文檔進行解析,最終將解析結果存入到一個List中,然後在上面代碼的rebuildUI方法中for循環遍歷讀取。

 

 

以下為Setting頁面的xml文檔:

 

 






    
    vcnlfd2lyZWxlc3NfbmV0d29ya3M=">

        
        

        
        

        
        

        
        

        
        
            
        

        
        

    

    
    

        
        
            
         

        
        

        
        

                
        
               
        
        

        
        
        

        
        

        
        

        
        

        
        


        
        

        
        

        
        
            
        

    

    
    

        
        

        
        

        
        

        
        

        
        
        
        
            
        

    


    

    
    

        
        

        
        

        
        

        
        

        
        

    


根據這個文件可看出來,dashboard-categories這個標簽對應著Java代碼中的List集合,dashboard-category這個標簽對應著DashboardCategory類,dashboard-tile這個標簽對應著DashboardTile這個類。

 

(2)處將通過for循環遍歷而來的數據通過創建DashboardTileView最終全部存入到mDashboard這個布局中,至此整個Setting模塊的界面布局已經完成了。

 

DashboardTileView.java

這個類是Setting中每個條目數據的類,通過onClick方法啟動不同的功能,比如WiFi,Bluetooth等

 

public class DashboardTileView extends FrameLayout implements View.OnClickListener {
    @Override
    public void onClick(View v) {
        if (mTile.fragment != null) {
            Utils.startWithFragment(getContext(), mTile.fragment, mTile.fragmentArguments, null, 0,
                    mTile.titleRes, mTile.getTitle(getResources()));
        } else if (mTile.intent != null) {
            getContext().startActivity(mTile.intent);
        }
    }
}


最終啟動不同的Setting子模塊,至此整個Setting模塊的整體框架就已分析結束了。

 

 

總結一下:

1、整個Setting模塊是在SettingActivity中加載DashboardSummary這個Fragment,然後從dashboard_categories.xml中讀取預先配置好的文件來初始化Settings的首界面視圖。

2、Setting的子界面基本上都是一個Fragment,並且基本上都是通過SettingActivity的OnCreate方法去加載的,同時大部分SubSetting在加載界面時,用的都是PreferenceFragment技術(在以後的博客中會講述)。

3、Android5.1的Setting使用的是DashboardCategory和DashboardTile類來存儲整個xml數據結構。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved