Android Settings 6.0 流程与定制修改

概述

android 6.0 版本的设置代码相比4.4就没有那么直白,但仍然可以用启动activity,界面布局,逻辑控制流程的顺序来阅读理解。

  1. 入口
    导入Settings源码同样以搜索android.intent.category.LAUNCHER的方式,可以找到启动activity名为Settings,打开代码:
public class Settings extends SettingsActivity {

    /*
    * Settings subclasses for launching independently.
    */
    public static class BluetoothSettingsActivity extends SettingsActivity { /* empty */ }
    public static class WirelessSettingsActivity extends SettingsActivity { /* empty */ }
    public static class SimSettingsActivity extends SettingsActivity { /* empty */ }
    public static class TetherSettingsActivity extends SettingsActivity { /* empty */ }
    public static class VpnSettingsActivity extends SettingsActivity { /* empty */ }
    

这里可以看到与4.4的不同,即通过常规启动activity形式找到的Settings并不是所熟悉的包含onCreate等生命周期,xml布局文件,一些控制逻辑这样形式的类,其主体定义的都是一些空实现的静态内部类,但这里有个比较明显的继承关系来自
SettingsActivity,其实从命名也可以猜测得到,这个类才是需要阅读理解的所在,打开查看:

public class SettingsActivity extends Activity

这就来到了熟悉的标准activity模式,这里同样结合运行界面找一下布局实现,自然先从onCreate开始:

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

当以点击Launcher图标的形式进来,这里的mIsShowingDashboard为true,即这个主activity引用的布局文件为 R.layout.settings_main_dashboard:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
             android:id="@+id/main_content"
             android:layout_height="match_parent"
             android:layout_width="match_parent"
             />

这里可以看到这个主布局,并没有太多确切内容,继续看可以发现:

if (!mIsShowingDashboard) {
                mDisplaySearch = false;
                // UP will be shown only if it is a sub settings
                if (mIsShortcut) {
                    mDisplayHomeAsUpEnabled = isSubSettings;
                } else if (isSubSettings) {
                    mDisplayHomeAsUpEnabled = true;
                } else {
                    mDisplayHomeAsUpEnabled = false;
                }
                setTitleFromIntent(intent);

                Bundle initialArguments = intent.getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
                switchToFragment(initialFragmentName, initialArguments, true, false,
                        mInitialTitleResId, mInitialTitle, false);
            } 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);
            }

之前提过mIsShowingDashboard为true,这里会走下面的分子,而switchToFragment运用的是FragmentTransaction替换Fragment的形式来填入实际内容,相信凡是接触过android应用开发对fragment的使用都不陌生,而这里正是标准的activity对应一个空的父布局,然后具体内容由具体的fragment填充;

这里不得不说android源码时常有让人无法理解的冗长调用关联,一个简单的功能能秀一二十个类或lib的调用,但又时常能发现这种最为基础,google大神程序员竟然也写了和自己这种初学者类似的代码而欣喜。

这里打开DashboardSummary,这里的流程又夹杂了一些调用,但仍然是从各个生命周期来分析,并且优先关注onCreateView界面到底如何实现,流程如下:

  1. onCreateView里主要是对整个大框架的定义,关键内容为mDashboard;
  2. 然后在onResume()找到了比较明显的sendRebuildUI()方法;
  3. 发现其实也就是经过handle机制执行到了rebuildUI(context);

而看到rebuildUI的代码便豁然开朗:

List<DashboardCategory> categories =
                ((SettingsActivity) context).getDashboardCategories(true);

关键就在这里获取了具体的DashboardCategory列表,也就是主界面一项项功能信息的内容,后续便是简单的循环解析,填充view,生成界面,而这里的来源竟然还是在SettingsActivity中:
getDashboardCategories > buildDashboardCategories:

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

到这里就可以知道具体的功能项信息由loadCategoriesFromResource 以XML解析的形式将R.xml.dashboard_categories内容封装到列表变量中,而下面的 updateTilesList(categories)就是4.4也有的针对内容在某些条件下移除一些选项;

对R.xml.dashboard_categories:

<dashboard-categories
        xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- WIRELESS and NETWORKS -->
    <dashboard-category
            android:id="@+id/wireless_section"
            android:key="@string/category_key_wireless"
            android:title="@string/header_category_wireless_networks" >

        <!-- Wifi -->
        <dashboard-tile
                android:id="@+id/wifi_settings"
                android:title="@string/wifi_settings_title"
                android:fragment="com.android.settings.wifi.WifiSettings"
                android:icon="@drawable/ic_settings_wireless"
                />

        <!-- Bluetooth -->
        <dashboard-tile
                android:id="@+id/bluetooth_settings"
                android:title="@string/bluetooth_settings_title"
                android:fragment="com.android.settings.bluetooth.BluetoothSettings"
                android:icon="@drawable/ic_settings_bluetooth"
                />

这就是和4.4的header类似的控件了,依然是每项对应一个功能项,并标有fragment属性,最终在DashboardSummary中封装具体内容,并添加到SettingsActivity的布局中去。

  1. 点击事件

可以发现在SettingsActivity以及DashboardSummary中都未发现明显的点击事件实现,那么点击每一项是如何进入子功能界面的呢;

其实在DashboardSummary的rebuildUI中可以发现,拿到List后,最终的一个个功能子项为DashboardTileView对象,这里打开其代码:

public class DashboardTileView extends FrameLayout implements View.OnClickListener {

可以发现其继承基本的FrameLayout,并清楚写明了点击事件调用到Utils.startWithFragment,最终即封装带有fragment信息的intent启动SubSettings,这也就是为什么每个功能项点击进入的都是SubSettings,而具体内容就根据fragment信息来实现。

3.定制化
常见的定制化即增删功能项,如果熟悉了以上流程,那么对于删减功能项就有太多的方式,从布局文件,到解析,到封装到列表,到updateTilesList,到addView,整个流程任何地方进行一下截断,添加个if之类的就可以去掉,这里不一一列出;

如果要增加一个功能项,这里同样类似于4.4如果要加一个自动开关机功能上去,那么就可以:

  1. 布局文件中dashboard_categories.xml中:
 2.        <!-- Schedule Power Alarm -->
 3.        <dashboard-tile
 4.                android:id="@+id/schedule_power_settings"
 5.                android:title="@string/schedule_power_settings_title"
 6.                android:fragment="com.android.settings.schedulePower.SchedulePowerSettings"
 7.                android:icon="@drawable/ic_settings_display"
 8.                />
 
         <!-- About Device -->
         <dashboard-tile

这里对应的资源文件另外添加,fragment可以先建一个空的类不写逻辑;

2.SettingsActivity加上新加的id以及fragment类名:

@@ -277,6 +278,7 @@ public class SettingsActivity extends Activity
             R.id.accessibility_settings,
             R.id.print_settings,
             R.id.nfc_payment_settings,
 1.            R.id.schedule_power_settings,
             R.id.home_settings,
             R.id.dashboard
     };
@@ -354,6 +356,7 @@ public class SettingsActivity extends Activity
             ProcessStatsSummary.class.getName(),
             DrawOverlayDetails.class.getName(),
             WriteSettingsDetails.class.getName(),
 2.            SchedulePowerSettings.class.getName()
     };

这样只要图片字符串资源都有定义,跳转的fragment不为空,编译apk push到机器后,即可看见新加的功能项,点击进入空的fragment,之后再具体完善逻辑功能即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值