ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Android 11 Settings源码入门,别再说自己不会了

2021-12-03 21:32:34  阅读:367  来源: 互联网

标签:11 Settings FRAGMENT args 源码 intent Intent SettingsActivity class


一,系统设置首页

Android系统设置的主界面是com.android.settings.Settings, 但是它只是一个activity-alias, 指向的是.homepage.SettingsHomepageActivity








需要注意的是通过命令(adb shell “dumpsys window | grep mCurrentFocus”)查看手机顶层activity时,打印出的不是targetActivity,而是这个activity-alias.

.homepage.SettingsHomepageActivity中的逻辑并不复杂,直接加载了TopLevelSettings这个Fragment

showFragment(new TopLevelSettings(), R.id.main_content);

TopLevelSettings通过AndroidXPreference来展示设置项列表,设置项列表的内容通过静态配置+动态添加的方式获取。

1,静态配置

所谓静态配置就是通过xml来配置。 如果你还不了解Preference,可以移步:www.jianshu.com/p/348eb0928… 简单了解一下

TopLevelSettings继承自抽象类DashboardFragment, 实现抽象方法getPreferenceScreenResId()并返回preference的配置文件即可完成静态配置。

@Override
protected int getPreferenceScreenResId() {
return R.xml.top_level_settings;
}

top_level_settings中配置了页面需要展示的配置项:

其中:

  • key:该配置项的主键

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享

title:配置项的标题

  • summary:概要标题下面的文字
  • icon:前面的图标
  • order:用来做排序的,值越小则排行越靠前
  • fragment:点击该item要跳转的界面
  • controller:该item的控制器,控制它的内容展示,是否可用,也可以控制它的点击事件
2,动态添加

动态获取是根据特殊的action标记,通过packageManger查询系统中安装的符合对应action的应用,将其动态添加到列表中。

例如:网络流量监控,存储空间管理,默认应用等配置项都是动态添加的。

具体实现可以参看文章:MTK快霸是如何动态加载的

二,系统设置其他界面

系统设置中除了.homepage.SettingsHomepageActivity,其他大部分的Activity都定义在Settings中, 并且继承自SettingsActivity, 但其中并没有实现任何逻辑。因此,这些Activity的逻辑都是在SettingsActivity中实现。

/**

  • Top-level Settings activity
    */
    public class Settings extends SettingsActivity {

/*

  • Settings subclasses for launching independently.
    /
    public static class AssistGestureSettingsActivity extends SettingsActivity { /
    empty /}
    public static class BluetoothSettingsActivity extends SettingsActivity { /
    empty / }
    public static class CreateShortcutActivity extends SettingsActivity { /
    empty / }
    public static class FaceSettingsActivity extends SettingsActivity { /
    empty / }
    public static class FingerprintSettingsActivity extends SettingsActivity { /
    empty */ }

    }

这些Activity中并没有实现任何逻辑,那它是怎么加载到自己应有的布局的呢?

在父类SettingsActivityonCreate()中:

@Override
protected void onCreate(Bundle savedState) {


// Should happen before any call to getIntent()
// 第一步
getMetaData();
// 第二步
final Intent intent = getIntent();
if (intent.hasExtra(EXTRA_UI_OPTIONS)) {
getWindow().setUiOptions(intent.getIntExtra(EXTRA_UI_OPTIONS, 0));
}

// Getting Intent properties can only be done after the super.onCreate(…)
final String initialFragmentName = intent.getStringExtra(EXTRA_SHOW_FRAGMENT);

// 第三步
launchSettingFragment(initialFragmentName, intent);


}

跟着上面的三个步骤:

第一步

首先通过getMetaData()获取该Activity在manifest中配置的fragment, 并赋值给mFragmentClass

public static final String META_DATA_KEY_FRAGMENT_CLASS = “com.android.settings.FRAGMENT_CLASS”;

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

那么manifest中是怎么配置的呢?如下:

由此可知WifiInfoActivity这个Acitivity对应的fragment是:com.android.settings.wifi.WifiInfo

第二步

通过getIntent()构造包含EXTRA_SHOW_FRAGMENT的intent

public Intent getIntent() {
Intent superIntent = super.getIntent();
String startingFragment = getStartingFragmentClass(superIntent);
// This is called from super.onCreate, isMultiPane() is not yet reliable
// Do not use onIsHidingHeaders either, which relies itself on this method
if (startingFragment != null) {
Intent modIntent = new Intent(superIntent);
modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);
Bundle args = superIntent.getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
if (args != null) {
args = new Bundle(args);
} else {
args = new Bundle();
}
args.putParcelable(“intent”, superIntent);
modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
return modIntent;
}
return superIntent;
}

/**

  • Checks if the component name in the intent is different from the Settings class and
  • returns the class name to load as a fragment.
    */
    private String getStartingFragmentClass(Intent intent) {
    // 存在mFragmentClass则直接返回
    if (mFragmentClass != null) return mFragmentClass;

String intentClass = intent.getComponent().getClassName();
if (intentClass.equals(getClass().getName())) return null;

if (“com.android.settings.RunningServices”.equals(intentClass)
|| “com.android.settings.applications.StorageUse”.equals(intentClass)) {
// Old names of manage apps.
intentClass = ManageApplications.class.getName();
}

return intentClass;
}

这里包含了mFragmentClass为空的情况,暂时先不管。

第三步

通过launchSettingFragment()启动对应Fragment,这里的initialFragmentName参数就是第二步Intent中包含的EXTRA_SHOW_FRAGMENT参数,mFragmentClass不为空的情况下传入的就是mFragmentClass

void launchSettingFragment(String initialFragmentName, Intent intent) {
if (initialFragmentName != null) {
setTitleFromIntent(intent);

Bundle initialArguments = intent.getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
switchToFragment(initialFragmentName, initialArguments, true,
mInitialTitleResId, mInitialTitle);
} else {
// Show search icon as up affordance if we are displaying the main Dashboard
mInitialTitleResId = R.string.dashboard_title;
switchToFragment(TopLevelSettings.class.getName(), null /* args */, false,
mInitialTitleResId, mInitialTitle);
}
}

switchToFragment()中将fragment添加到activity中。

/**

  • Switch to a specific Fragment with taking care of validation, Title and BackStack
    */
    private Fragment switchToFragment(String fragmentName, Bundle args, boolean validate,
    int titleResId, CharSequence title) {
    Log.d(LOG_TAG, "Switching to fragment " + fragmentName);
    if (validate && !isValidFragment(fragmentName)) {
    throw new IllegalArgumentException("Invalid fragment for this activity: "
  • fragmentName);
    }
    // 反射创建fragment
    Fragment f = Utils.getTargetFragment(this, fragmentName, args);
    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    transaction.replace(R.id.main_content, f);
    if (titleResId > 0) {
    transaction.setBreadCrumbTitle(titleResId);
    } else if (title != null) {
    transaction.setBreadCrumbTitle(title);
    }
    // 提交事务
    transaction.commitAllowingStateLoss();

标签:11,Settings,FRAGMENT,args,源码,intent,Intent,SettingsActivity,class
来源: https://blog.csdn.net/m0_64382743/article/details/121707467

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有