android setting 分析,Android 8 setting源码分析三

以setting—>system—>Languages & input—>Languages 这个点击路径来说,图1依托于Settings图2依托于.Settings$xxxActivity,图三和图4是在hierarchy view中显示为SubSettings。(别的不一定,例如Display中并没有依托于SubSettings)。

e75bcd4fc1f5

图1

e75bcd4fc1f5

图2

e75bcd4fc1f5

图3

e75bcd4fc1f5

图4

e75bcd4fc1f5

image.png

那么SubSettings和Settings以及Settings$xxxActivity的差别是什么?

//packages\apps\Settings\src\com\android\settings\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.

*/

public class SubSettings extends SettingsActivity {

@Override

public boolean onNavigateUp() {

finish();

return true;

}

@Override

protected boolean isValidFragment(String fragmentName) {

Log.d("SubSettings", "Launching fragment " + fragmentName);

return true;

}

}

/**

* Top-level Settings activity

*/

public class Settings extends SettingsActivity {

.........

public static class LanguageAndInputSettingsActivity extends SettingsActivity { /* empty */ }

.........

public static class SystemDashboardActivity extends SettingsActivity {}

}

从定义上来看,虽然Settings 和SubSettings 都是继承自SettingsActivity ,但是Settings中只是定义了一堆不重写函数的Settings$xxxActivity,SubSettings 中简单定义了几个函数,目前看不出差异。

//AndroidManifest.xml

......

android:label="@string/header_category_system"

android:icon="@drawable/ic_settings_about">

android:value="com.android.settings.category.ia.homepage"/>

android:value="com.android.settings.system.SystemDashboardFragment"/>

android:resource="@string/system_dashboard_summary"/>

......

android:label="@string/language_settings"

android:icon="@drawable/ic_settings_language"

android:taskAffinity="com.android.settings"

android:parentActivityName="Settings$SystemDashboardActivity">

android:value="com.android.settings.category.ia.system"/>

android:value="com.android.settings.language.LanguageAndInputSettings"/>

android:value="true"/>

......

图三显示的是.Settings$LanguageAndInputSettingsActivity,LanguageAndInputSettingsActivity是由LanguageAndInputSettings这个fragment具体定义显示的内容,而LanguageAndInputSettings extends DashboardFragment,与此同时,上一级的SystemDashboardFragment也是继承自DashboardFragment,并且SystemDashboardActivity 的写法也是与LanguageAndInputSettingsActivity类似, 都是定义在Settings类中的,并且fragment的显示也都是通过SettingsActivity中的launchSettingFragment函数去显示。那么又是怎么跟SubSettings 扯上关系?为什么LanguageAndInputSettingsActivity在hierarchy view中显示的是SubSettings,而SystemDashboardActivity 是Settings$SystemDashboardActivity。

由于SettingsActivity中判断条件是

final boolean isSubSettings = this instanceof SubSettings || intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SUBSETTING, false);

通过打印log

Log.d(TAG,"this instanceof SubSettings = " + String.valueOf(this instanceof SubSettings) + " , getBooleanExtra " + String.valueOf(intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SUBSETTING, false)));

发现

01-02 01:43:22.792 1155-1155/? D/SettingsActivity: this instanceof SubSettings = true , getBooleanExtra false

判断是否为SubSettings关键在this instanceof SubSettings。那么为什么LanguageAndInputSettingsActivity在hierarchy view中显示是SubSettings?

在点击system下的Languages & input 的时候,会调用SettingsActivity中的startPreferencePanel函数。

//vendor\mediatek\proprietary\packages\xx\xx\src\com\android\settings\SettingsActivity.java

/**

* Start a new fragment containing a preference panel. If the preferences

* are being displayed in multi-pane mode, the given fragment class will

* be instantiated and placed in the appropriate pane. If running in

* single-pane mode, a new activity will be launched in which to show the

* fragment.

*

* @param fragmentClass Full name of the class implementing the fragment.

* @param args Any desired arguments to supply to the fragment.

* @param titleRes Optional resource identifier of the title of this

* fragment.

* @param titleText Optional text of the title of this fragment.

* @param resultTo Optional fragment that result data should be sent to.

* If non-null, resultTo.onActivityResult() will be called when this

* preference panel is done. The launched panel must use

* {@link #finishPreferencePanel(Fragment, int, Intent)} when done.

* @param resultRequestCode If resultTo is non-null, this is the caller's

* request code to be received with the result.

*/

public void startPreferencePanel(Fragment caller, String fragmentClass, Bundle args,

int titleRes, CharSequence titleText, Fragment resultTo, int resultRequestCode) {

Log.d(TAG,"startPreferencePanel");

String title = null;

if (titleRes < 0) {

if (titleText != null) {

title = titleText.toString();

} else {

// There not much we can do in that case

title = "";

}

}

Utils.startWithFragment(this, fragmentClass, args, resultTo, resultRequestCode,

titleRes, title, mIsShortcut, mMetricsFeatureProvider.getMetricsCategory(caller));

}

而startWithFragment中又调用了onBuildStartFragmentIntent,这里构造了一个intent, intent.setClass(context, SubSettings.class),ComponentName的class为SubSettings,因此hierarchy view中显示SubSettings,而没有显示真正的activity的名字。至于这样做的原因,由于本人知识的局限性,目前没有想到。

//vendor\mediatek\proprietary\packages\xx\xx\src\com\android\settings\Utils.java

......

public static void startWithFragment(Context context, String fragmentName, Bundle args,

Fragment resultTo, int resultRequestCode, int titleResId,

CharSequence title, boolean isShortcut, int metricsCategory) {

Intent intent = onBuildStartFragmentIntent(context, fragmentName, args,

null /* titleResPackageName */, titleResId, title, isShortcut, metricsCategory);

if (resultTo == null) {

context.startActivity(intent);

} else {

resultTo.getActivity().startActivityForResult(intent, resultRequestCode);

}

}

........

public static Intent onBuildStartFragmentIntent(Context context, String fragmentName,

Bundle args, String titleResPackageName, int titleResId, CharSequence title,

boolean isShortcut, int sourceMetricsCategory) {

Log.d(TAG,"onBuildStartFragmentIntent");

Intent intent = new Intent(Intent.ACTION_MAIN);

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

intent.putExtra(SettingsActivity.EXTRA_SOURCE_METRICS_CATEGORY, sourceMetricsCategory);

return intent;

}

.............

到了这里,基本上捋清楚了显示流程。

总结就是:通过SettingsActivity中的switchToFragment,去显示所有的界面,其他的这些定义的activity只是一个用来定义fragment的壳子。

另外,使用中可能需要通过intent跳转到setting中的界面。如

startActivity(new Intent(Settings.ACTION_SETTINGS));

根据官方文档

https://developer.android.com/reference/android/provider/Settings.html#ACTION_APP_NOTIFICATION_SETTINGS可知

Settings.ACTION_SETTINGS ,Constant Value: "android.settings.SETTINGS"即下面AndroidManifest.xml中的action 标签中的所定义的name。

android:taskAffinity="com.android.settings"

android:label="@string/settings_label_launcher"

android:launchMode="singleTask">

android:value="true" />

.........................

android:exported="true">

android:value="com.android.settings.notification.AppNotificationSettings" />

因此,如果新增的activity,只要定义新的action然后使用这个string去新建intent,最后通过startActivity(intent)跳转。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值