点击事件回调堆栈.png
我们知道在Settings中,各模块的Fragment基本都继承了DashboardFragment,当有点击事件时,就会回调DashboardFragment中的onPreferenceTreeClick()方法:
@Override public boolean onPreferenceTreeClick(Preference preference) { final Collection<List<AbstractPreferenceController>> controllers = mPreferenceControllers.values(); for (List<AbstractPreferenceController> controllerList : controllers) { for (AbstractPreferenceController controller : controllerList) { if (controller.handlePreferenceTreeClick(preference)) { // log here since calling super.onPreferenceTreeClick will be skipped writePreferenceClickMetric(preference); return true; } } } return super.onPreferenceTreeClick(preference); }
在onPreferenceTreeClick()方法中可以根据preference的key做事件拦截,如果不会拦截,将会调用到父类InstrumentedPreferenceFragment的onPreferenceTreeClick()方法:
@Override public boolean onPreferenceTreeClick(Preference preference) { writePreferenceClickMetric(preference); return super.onPreferenceTreeClick(preference); }
在该方法中,又将会调用到androidx中的PreferenceFragmentCompat方法中,由于androidx中源码不开放,就不做分析,但下一步回将调到SettingsActivity中的onPreferenceStartFragment()方法:
@Override public boolean onPreferenceStartFragment(PreferenceFragmentCompat caller, Preference pref) { new SubSettingLauncher(this) .setDestination(pref.getFragment()) .setArguments(pref.getExtras()) .setSourceMetricsCategory(caller instanceof Instrumentable ? ((Instrumentable) caller).getMetricsCategory() : Instrumentable.METRICS_CATEGORY_UNKNOWN) .setTitleRes(-1) .launch(); return true; }
在该方法中由SubSettingLauncher类里面的launch()方法,启动了对应的空Activity,但在Setting中各模块的Activity都时继承SettingsActivity的。但对应的空Activity启动时,就会回执行SettingsActivity中onCreate()方法:
@Override protected void onCreate(Bundle savedState) { super.onCreate(savedState); long startTime = System.currentTimeMillis(); //工厂类实现方法com.android.settings.overlay.FeatureFactoryImpl.java final FeatureFactory factory = FeatureFactory.getFactory(this); //获取菜单信息的工厂类,实现类为DashboardFeatureProviderImpl.java mDashboardFeatureProvider = factory.getDashboardFeatureProvider(this); mMetricsFeatureProvider = factory.getMetricsFeatureProvider(); // 第一步 从intent信息中获取<meta-data/>标签名为"com.android.settings.FRAGMENT_CLASS"的值(下文用于加载Fragment的类名) getMetaData(); // 第二步 final Intent intent = getIntent(); if (intent.hasExtra(EXTRA_UI_OPTIONS)) { getWindow().setUiOptions(intent.getIntExtra(EXTRA_UI_OPTIONS, 0)); } //获取上面getMetaData()得到的类名 final String initialFragmentName = intent.getStringExtra(EXTRA_SHOW_FRAGMENT); //是否为快捷进入方式(如从其它的应用进入Settings的某个设置项) mIsShortcut = isShortCutIntent(intent) || isLikeShortCutIntent(intent) || intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SHORTCUT, false); ... ... if (savedState != null) { ... ... } else { // 第三步 加载布局 launchSettingFragment(initialFragmentName, isSubSettings, intent); } ... ... }
最终在 launchSettingFragment(initialFragmentName, isSubSettings, intent) 方法中加载相对应的Fragment布局,(若注释这句话:你会发现 Activity 启动了,却没有布局)。