前述:

本人已工作两年多,但是依然感觉还是Android的门外汉,之前一直从事Android的应用开发,每天就是各种调用SDK方法,各种拷贝网上的源码以及jar包,从来也不管为啥这样用,由于换了一份工作才开始接触到Android的源码,感觉Android的水好深啊。

今天这篇博客也是我的处女作啊,以后也希望通过多多研究源码来写出更多的博客,我觉得写博客主要还是作为一个记录吧,不然感觉有的东西真的很容易丢,尤其是平时不怎么接触的模块。

好啦,接下来开始今天的Setting旅行啦。


Settings简述:

Setting模块大家还是比较熟悉的吧?其实Setting也不是什么高级的东西,它就是一个APP,属于Android的应用层,源码在packages\apps\Settings中,今天分析的源码是基于Android5.1,如下图是5.1Setting模块的界面:

Android 5.1 Settings模块源码分析_第1张图片


查看一个应用首先是查看这个应用的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 Intentfinal 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

同时继续往下走,会看到这段代码块:

if (savedState != null) {   ...         } else {    if (!mIsShowingDashboard) {      ...    } else {// No UP affordance if we are displaying the main DashboardmDisplayHomeAsUpEnabled = 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文档:


<?xml version="1.0" encoding="utf-8"?>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    

根据这个文件可看出来,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. Android方法数
  2. 改变Android按钮背景颜色的高效方法
  3. Android双击返回键退出程序的实现方法
  4. Android异步加载全解析之Bitmap
  5. 混合开发之ReactNative调用Android原生方法
  6. Android投屏电脑反向控制软件QtScrcpy使用方法
  7. Android中Activity全局共享方法AppContext
  8. 查看Android内存的8中方法
  9. Window下android 模拟器SD卡的使用方法

随机推荐

  1. Android(安卓)studio 打包aar库
  2. Android事件分发机制完全解析,带你从源码
  3. 图解Android(安卓)View的scrollTo(),scro
  4. 钉钉开发Android调试微应用
  5. android源码下载以及编译
  6. Android(安卓)获取Google Weather API 并
  7. Android(安卓)动画机制(一)
  8. 【Android】音乐播放器边播边缓存(三)Andro
  9. Android忘记密码功能实现
  10. 【Android(安卓)对话框(Dialog)大全 建立