通过上面知道,SettingsHomepageActivity 直接加载了TopLevelSettings这个Fragment。而该Fragment继承了DashboardFragment,先来看TopLevelSettings的构造方法:
public TopLevelSettings() { final Bundle args = new Bundle(); // Disable the search icon because this page uses a full search view in actionbar. args.putBoolean(NEED_SEARCH_ICON_IN_ACTION_BAR, false); setArguments(args); }可以看到构造方法中仅设置了个标记位,再根据framgments生命周期先来看onAttach()方法:
@Override public void onAttach(Context context) { super.onAttach(context); use(SupportPreferenceController.class).setActivity(getActivity()); }调用父类DashboardFragment.java的onAttach()方法,此方法重要是完成mPreferenceControllers的加载。
接着看onCreate()方法,由于TopLevelSettings未重写父类的方法,以是直接看父类DashboardFragment的onCreate()方法。
@Override public void onCreate(Bundle icicle) { super.onCreate(icicle); // Set ComparisonCallback so we get better animation when list changes. getPreferenceManager().setPreferenceComparisonCallback( new PreferenceManager.SimplePreferenceComparisonCallback()); if (icicle != null) { // Upon rotation configuration change we need to update preference states before any // editing dialog is recreated (that would happen before onResume is called). updatePreferenceStates(); } }根据log定位发现,其后调用DashboardFragment.java的onCreatePreferences()方法:这里我也不知道怎么调用到这来的,哈哈。
@Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { refreshAllPreferences(getLogTag()); } /** * Refresh all preference items, including both static prefs from xml, and dynamic items from * DashboardCategory. */ private void refreshAllPreferences(final String TAG) { final PreferenceScreen screen = getPreferenceScreen(); // First remove old preferences. if (screen != null) { // Intentionally do not cache PreferenceScreen because it will be recreated later. screen.removeAll(); } // Add resource based tiles. displayResourceTiles(); refreshDashboardTiles(TAG); final Activity activity = getActivity(); if (activity != null) { Log.d(TAG, "All preferences added, reporting fully drawn"); activity.reportFullyDrawn(); } updatePreferenceVisibility(mPreferenceControllers); }以看到此方法重要是用来加载体现的preference items,重要分为两部门,一个是静态xml界说的prefs(调用displayResourceTiles()方法),另一部门是从DashboardCategory动态加载(调用refreshDashboardTiles(TAG)方法,此中TAG为 “TopLevelSettings”)。
displayResourceTiles()
此方法重要是从xml资源文件中加载体现prefs:
/** * Displays resource based tiles. */ private void displayResourceTiles() { final int resId = getPreferenceScreenResId(); if (resId <= 0) { return; } addPreferencesFromResource(resId); final PreferenceScreen screen = getPreferenceScreen(); screen.setOnExpandButtonClickListener(this); mPreferenceControllers.values().stream().flatMap(Collection::stream).forEach( controller -> controller.displayPreference(screen)); }起首调用getPreferenceScreenResId()方法获取所要加载的xml的ID:
@Override protected abstract int getPreferenceScreenResId();终极回调用到子类TopLevelSettings.java的getPreferenceScreenResId()方法:
@Override protected int getPreferenceScreenResId() { return R.xml.top_level_settings; }此重要是调用androidX Preference的addPreferencesFromResource()方法。此方法重要是将preferenceScreen下全部Preference添加到ArrayList中,然后再根据此聚集构建天生PreferenceGroupAdapter,末了将此adapter设置到listview中,完成数据绑定,从而完成界面加载。在这里就要明白mPreferenceControllers是什么,在哪初始化的?
我们很快就可以找到:在onAttach()中添加的。
final List<AbstractPreferenceController> controllers = new ArrayList<>(); // Load preference controllers from code final List<AbstractPreferenceController> controllersFromCode = createPreferenceControllers(context); // Load preference controllers from xml definition final List<BasePreferenceController> controllersFromXml = PreferenceControllerListHelper .getPreferenceControllersFromXml(context, getPreferenceScreenResId()); // Filter xml-based controllers in case a similar controller is created from code already. final List<BasePreferenceController> uniqueControllerFromXml = PreferenceControllerListHelper.filterControllers( controllersFromXml, controllersFromCode); // Add unique controllers to list. if (controllersFromCode != null) { controllers.addAll(controllersFromCode); } controllers.addAll(uniqueControllerFromXml); // And wire up with lifecycle. final Lifecycle lifecycle = getSettingsLifecycle(); uniqueControllerFromXml .stream() .filter(controller -> controller instanceof LifecycleObserver) .forEach( controller -> lifecycle.addObserver((LifecycleObserver) controller)); mPlaceholderPreferenceController = new DashboardTilePlaceholderPreferenceController(context); controllers.add(mPlaceholderPreferenceController); for (AbstractPreferenceController controller : controllers) { addPreferenceController(controller); }可以发现:
1、从代码中加载preference controllers,调用createPreferenceControllers()方法;
2、从xml界说中加载preference controllers,调用getPreferenceControllersFromXml()方法。
3、过滤重复界说的controller等,赋值添补mPreferenceControllers。
再回到displayResourceTiles()方法中的:
mPreferenceControllers.values().stream().flatMap(Collection::stream).forEach( controller -> controller.displayPreference(screen));此语句重要就是调用各个controller的displayPreference()方法。
以网络和互联网菜单项为例,xml中设置的controller为"com.android.settings.network.TopLevelNetworkEntryPreferenceController",检察TopLevelNetworkEntryPreferenceController.java发现,其内并未实现displayPreference()方法,检察继承关系:是继承BasePreferenceController的,接着检察BasePreferenceController中的displayPreference()方法。
/** * Displays preference in this controller. */ @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); if (getAvailabilityStatus() == DISABLED_DEPENDENT_SETTING) { // Disable preference if it depends on another setting. final Preference preference = screen.findPreference(getPreferenceKey()); if (preference != null) { preference.setEnabled(false); } } }又是调用BasePreferenceController父类AbstractPreferenceController中的displayPreference:
/** * Displays preference in this controller. */ public void displayPreference(PreferenceScreen screen) { final String prefKey = getPreferenceKey(); if (TextUtils.isEmpty(prefKey)) { Log.w(TAG, "Skipping displayPreference because key is empty:" + getClass().getName()); return; } if (isAvailable()) { setVisible(screen, prefKey, true /* visible */); if (this instanceof Preference.OnPreferenceChangeListener) { final Preference preference = screen.findPreference(prefKey); preference.setOnPreferenceChangeListener( (Preference.OnPreferenceChangeListener) this); } } else { setVisible(screen, prefKey, false /* visible */); } }1、getPreferenceKey()获取preference的key,会调用到子类BasePreferenceController.java的getPreferenceKey()方法:
@Override public String getPreferenceKey() { return mPreferenceKey; }而据上面分析到mPreferenceKey实质上即为xml中每个preference设置的android:key属性的值,即此处应为"top_level_network"。(以网络和互联网菜单项为例)
2、isAvailable();判断此preference是否可用便是否应该被体现。假如返回true,则被体现出来,反之则不被体现,终极也会调用到BasePreferenceController.java的isAvailable()方法:
@Override public final boolean isAvailable() { final int availabilityStatus = getAvailabilityStatus(); return (availabilityStatus == AVAILABLE || availabilityStatus == AVAILABLE_UNSEARCHABLE || availabilityStatus == DISABLED_DEPENDENT_SETTING); }注意:看这里的BasePreferenceController.java中的isAvailable()方法中的getAvailabilityStatus(),不停跟进去,会发现调用的是:BasePreferenceController子类TopLevelNetworkEntryPreferenceController.java的getAvailabilityStatus()方法:
@Override public int getAvailabilityStatus() { return Utils.isDemoUser(mContext) ? UNSUPPORTED_ON_DEVICE : AVAILABLE_UNSEARCHABLE; }3、 调用setVisible()方法设置是否可被体现:setVisible(screen, prefKey, true /* visible */);
// frameworks/base/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java protected final void setVisible(PreferenceGroup group, String key, boolean isVisible) { final Preference pref = group.findPreference(key); if (pref != null) { pref.setVisible(isVisible); } }4、判断controller是否实现了Preference.OnPreferenceChangeListener接口,是,则设置监听。
综上,假如盼望preference不被表如今界面上,可以通过实现相关preference的controller的getAvailabilityStatus()方法,使此方法的返回值不为AVAILABLE、AVAILABLE_UNSEARCHABLE、DISABLED_DEPENDENT_SETTING即可。
2、继承看检察BasePreferenceController.java的displayPreference()方法的剩余语句:
if (getAvailabilityStatus() == DISABLED_DEPENDENT_SETTING) { // Disable preference if it depends on another setting. final Preference preference = screen.findPreference(getPreferenceKey()); if (preference != null) { preference.setEnabled(false); } }根据子类controller实现的getAvailabilityStatus()方法的返回值判断是否须要将此preference置为不可点击。
至此,DashboardFragment.java中displayResourceTiles()方法分析完成。
总结: