zoukankan      html  css  js  c++  java
  • 关于Android Settings中的八个问题

    本问将回答以下八个问题,如有错误,敬请批评指正,不胜感激!(注:本文中的Settings解析基于android4.0+)

    问题一Settings的主界面是怎么实现的?

    问题二为什么使用hierarchyviewer Settings中的很多界面显示的都是SubSettings

    问题三hierarchyviewer 中显示SubSetting时如何确定我进入的是哪个fragment

    问题四、点击设置界面的某一个header时,设置界面是如何切换的?

    问题五Settings.javagetMetaDatagetStartingFragmentClass这两个函数是否有点矛盾?

    问题六Settingsshortcut是如何创建的?从shortcut进入Settings的流程是什么?

    问题七、为什么我从Settingsshortcut进入时,hierarchyviewer显示的就不是SubSettings(Data usage)

    问题八Settings.java中很多继承自它的内部类都是空实现,为什么要写这些类?

    -----------------------------------------------------------------------------------------------------------------------------------------

    由于项目需要,本人就对Android中的Settings进行了解析,希望能帮到对Settings有兴趣的同志们~

    -----------------------------------------------------------------------------------------------------------------------------------------

    问题一、Settings的主界面是怎么实现的?

    为了能适应平板和手机,Settings采用了PreferenceActivityPreferenceFragment结合的实现方式。

    Settings.java继承自PreferenceActivity,是Settings的主界面,它通过loadHeadersFromResource函数(api level 11)加载res/xml/settings_headers.xml来构造界面。在settings_headers.xml中声明了要在Settings主界面显示的各个header(如SoundDisplay等)。Settings.HeaderAdapter将其中的header分为三类。在Settings.HeaderAdapter中的getView方法中根据header的类型使用不同的布局文件。

    header划分类型的函数

            static int getHeaderType(Header header) {
    
                if (header.fragment == null && header.intent == null) {
    
                    return HEADER_TYPE_CATEGORY; // 因为没有指明fragment和intent
    
                } else if (header.id == R.id.wifi_settings || header.id == R.id.bluetooth_settings || header.id == R.id.mobiledata_settings) {
    
                    return HEADER_TYPE_SWITCH; // 针对特定的三个header,分别为Wi-Fi、Bluetooth和Mobile data
    
                } else {
    
                    return HEADER_TYPE_NORMAL;
    
                }
    
            }

    当我们点击主界面的header后会显示与该header相关的设置界面。大部分(Display的详细设置界面)都是通过继承PreferenceFragment来实现的;有一部分是在settings_headers.xml中声明<intent>,当被点击时(触发PreferenceActivityonHeaderClick())将会通过startActivity来启动在<intent>节点中声明的targetClass(如设置中的Add account)

    问题二、为什么使用hierarchyviewer Settings中的很多界面显示的都是SubSettings

    要解决这个问题我们先要清楚为什么会写一个SubSettings.java继承自Settings.java

    SubSettings.java中的注释很清楚的告诉了我们原因:

    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在声明时指定了android:launchMode="singleTask"

    我们知道,要显示Fragment的内容,我们就需要为其指定一个Activity。而Settings中的很多设置界面是由PreferenceFragment来完成的,当然也需要我们指定Activity.

    onBuildStartFragmentIntent函数会为我们构造一个显示FragmentIntent对象(该函数的注释写的非常明白).Settings.java重写了这个函数(注,重写时它调用了super的该方法),在为intent对象setClass时都使用SubSettings.java.(注:在settings_headers.xml指定了intentheader是不会触发onBuildStartFragmentIntent)

    结果就是,Settings中大部分fragment都是使用的SubSettings这个Activity来显示。由于hierarchyviewer只是显示当前界面使用的Activity(不能显示这个界面是由哪个Fragment构造的),所以我们使用hierarchyviewer Settings进行观察时很多设置界面显示的是SubSettings

    问题三、hierarchyviewer 中显示SubSetting时如何确定我进入的是哪个fragment

    res/xml/settings_headers.xml中声明了各个header被点击后使用的fragment。我们可以根据这个文件确定我们进入的fragment

    例如,当我们点击Displayhierarchyviewer 中显示SubSetting。我们通过查找settings_headers就可知道使用的是哪个fragment

    Display这个headersettings_headers.xml中的声明:

        <!-- Display -->
    
        <header
    
            android:id="@+id/display_settings"
    
            android:icon="@drawable/ic_settings_display"
    
            android:fragment="com.android.settings.DisplaySettings"
    
            android:title="@string/display_settings" />

     header中使用 android:fragment指明使用的fragment。由此可知,Display使用的是com.android.settings.DisplaySettings这个fragment

    问题四、点击设置界面的某一个header时,设置界面是如何切换的? 

    点击设置界面的header,会触发SettingsonHeaderClick函数,主要的处理都在其父类PreferenceActivityonHeaderClick中实现的。如果这个header指定了fragment,在mSinglePane(标识是否为小屏幕设备。如,区分手机还是平板)true时,会调用startWithFragment方法,在startWithFragment方法中将调用onBuildStartFragmentIntent方法来构造intent对象(重要),最后使用该intent对象启动一个activity来显示fragment

    以点击Settings中的Display为例.

    (Bluetooth同理,只不过启动的Activity变为BluetoothSettingsActivity(继承自Settings,但是没有实现重写任何方法,所以与SubSettings是一样的处理),fragment变为 com.android.settings.bluetooth.BluetoothSettings)

    fragmentcom.android.settings.DisplaySettingsactivitycom.android.settings.SubSettings.fragment是由onHeaderClick函数传入的,activity是由onBuildStartFragmentIntent()指定的)

    执行startActivity后将启动SubSettings.java。即我们将会再一次执行SubSettingsPreferenceActivityonCreate方法(因为Settings.javaonCreate方法调用了super.onCreate()),但是这次并不会进入Settings的主界面,因为我们的使用的intent对象是有很大不同的。这一次onCreate函数(PreferenceActivity)中的initialFragment 将被初始化为com.android.settings.DisplaySettings然后我们将进入switchToHeader(),最后switchToHeaderInner会取得FragmentTransaction对象,然后执行了transaction.replace(com.android.internal.R.id.prefs, f).就这样把我们的fragment显示出来了。在onCreate中会对其他viewvisibility进行设置,以保证只显示prefs。如,com.android.internal.R.id.headersvisibility设置为VIEW.GONE.

    PreferenceActivity的布局文件为preference_list_content.xml

    问题五、Settings.javagetMetaDatagetStartingFragmentClass这两个函数是否有点矛盾?

    这两个函数可以说是相辅相成的(好官方,^_^)。getMetaData会从AndroidManifest.xml中读取Activity<meta-data>节点的数据;getStartingFragmentClass则从启动Activityintent中读取数据。这两个函数会对读取到的数据进行整合,getStartingFragmentClass依赖于getMetaData读取到的数据,但是它也可能对数据作出修改(为了兼容性,如对原有manage apps类进行特殊处理)

    问题六、Settingsshortcut是如何创建的?从shortcut进入Settings的流程是什么?

    创建SettingsshortcutLuancher将会启动CreateShortcut,创建shortcut所需的intent对象将会由CreateShortcut和其父类LuancherActivity共同构建(详见 CreateShortcutonListItemClick),这时创建的Intent对象使用的就不是SubSettings(LuancherActivityintentForPosition函数执行setClassName()时使用的参数并不是SubSettings).

    CreateShortcut中列出了可以创建shortcut的设置项,这些设置项怎样检索出来的?

    原来,在创建LuancherActivityActivityAdapter对象时,其构造函数中执行了makeListItems函数,该函数将使用PackageManagerqueryIntentActivities来根据intent对象查询符合条件的activity。使用的intent是从getTargetIntent函数返回的。不难发现,要想在CreateShortcut中显示,Activity在必须要有

    <category android:name="com.android.settings.SHORTCUT" />

    如果我们想将Security设置项添加到shortcut列表,我们只需要在androidmanifest.xml中声明Settings$SecuritySettingsActivity部分加上

    <category android:name="com.android.settings.SHORTCUT" />

    即可。

    回到正题,点击shortcut进入Settings,传入Intent对象中包含了目标fragment和目标activity以及其他信息。PreferenceActivity得到了足够多的信息,因此在onCreate中将依次执行switchToHeader()->setSelectedHeader(null)->switchToHeaderInner()->transaction.replace(com.android.internal.R.id.prefs, f);

    这样就完成了fragment的显示(使用的activity是从intent解析出来的.switchToHeaderInner中执行Fragment.instantiate时使用的Contextthis!!)像执行onHeaderClick那样会执行函数onBuildStartFragmentIntent(Settings中重写了该函数)重新指定我们使用的Activity

    问题七、为什么我从Settingsshortcut进入时,hierarchyviewer显示的就不是SubSettings(Data usage)

    hierarchyviewer中显示SubSettings是因为我们在onBuildStartFragmentIntent方法中做了特殊处理(详见问题二)。从shortcut进入Settings时不显示SubSettings是因为没有走这个函数,因此就不会显示为SubSettings(详见问题六)

    问题八、Settings.java中很多继承自它的内部类都是空实现,为什么要写这些类?

    我们从这些内部类的名字可以看出它们的主要作用,如BluetoothSettingsActivity是针对蓝牙设置的。空实现说明他们都将使用Settings.java中的函数(注意private的属性和方法的访问权限问题)。声明这些Activity的原因我认为主要是为了提高各个设置项、整个Settings的灵活性,方便开发者进行扩展。除此之外的一些原因:可以让我们为单独的设置项添加 shortcut(data usage),因为创建shortcut使用queryIntentActivities查询使用的activity;允许其它程序访问单独的设置项;结构设计需要,启动Activity会读取meta-data信息;某些设置项不想使用SubSettings的属性。如,Settings中点击Bluetooth时使用BluetoothSettingsActivity,启动Bluetooth时将使用BluetoothSettingsActivity的属性,如 android:clearTaskOnLaunch="true"

    写的不全,望补充~

     

  • 相关阅读:
    Atitit attilax要工作研究的要素 纪要 方案 趋势 方向 概念 理论
    Atitit 常见每日流程日程日常工作.docx v7 r8f
    Atitit it 互联网 软件牛人的博客列表
    Atitit 信息链(Information Chain)的概念理解 attilax总结
    Atitit 知识点的体系化 框架与方法 如何了解 看待xxx
    Atitit 聚合搜索多个微博 attilax总结
    Atitit 企业知识管理PKM与PIM
    Atitit 项目沟通管理 Atitit 沟通之道 attilax著.docx
    Atitit 项目管理软件 在线服务 attilax总结 1. 项目管理协作的历史 1 1.1. Worktile 406k 1 1.2. Teambition  584k in baidu
    Atitit.每周末总结 于每周一计划日程表 流程表 v8 import 上周遗漏日志补充 检查话费 检查流量情况 Crm问候 Crm表total and 问候
  • 原文地址:https://www.cnblogs.com/Lefter/p/3048010.html
Copyright © 2011-2022 走看看