Android(安卓)7.0 Settings Summary 小记
改Setting的主菜单的一个显示问题,发现android原生的Settings 在7.0 发生了很大的变化。
主要有:
1、增加了侧滑菜单;
2、增加了Suggestions
3、可以在主界面显示状态(这篇博客主要针对这个)
4、主界面使用RecyclerView
这个是主界面加载的时序图
本文主要介绍下 Summary的显示流程
通过搜索可以定位到这个配置的地方是在 下面代码加粗的地方配置
public void setListening(boolean listening) { if (listening) { // TODO: Listen. BatteryInfo.getBatteryInfo(mContext, new BatteryInfo.Callback() { @Override public void onBatteryInfoLoaded(BatteryInfo info) { *mLoader.setSummary(SummaryProvider.this, "("+(int)BatteryCapcityValue+"mAh)"+info.mChargeLabelString);* } }); } }
知其然要知其所以然 所以今天分析下为什么一个Summary 需要在这个地方配置。
进入setSummary 方法
public void setSummary(SummaryProvider provider, final CharSequence summary) { final ComponentName component= mSummaryMap.get(provider); mHandler.post(new Runnable() { @Override public void run() { // Since tiles are not always cached (like on locale change for instance), // we need to always get the latest one. Tile tile = mAdapter.getTile(component); if (tile == null) return; if (DEBUG) Log.d(TAG, "setSummary " + tile.title + " - " + summary); tile.summary = summary; mAdapter.notifyChanged(tile); } }); }
可以发现主要就是设置titile的summary 然后通知Adapter更新,而Adapter 是DashboardAdapter的实例,是设置给DashboardSummary的,通过上面的时序图其实可以Settings的布局其实就是在DashboardSummary中进行处理的。
而mLoader.setSummary(SummaryProvider.this, “(“+(int)BatteryCapcityValue+”mAh)”+info.mChargeLabelString);又是在什么时候调用的呢
通过时序图可以发现在DashboardSummary中的oncreate中
public void onCreate(Bundle savedInstanceState) { long startTime = System.currentTimeMillis(); super.onCreate(savedInstanceState); List categories = ((SettingsActivity) getActivity()).getDashboardCategories(); **mSummaryLoader = new SummaryLoader(getActivity(), categories);** setHasOptionsMenu(true); Context context = getContext(); mConditionManager = ConditionManager.get(context, false); mSuggestionParser = new SuggestionParser(context, context.getSharedPreferences(SUGGESTIONS, 0), R.xml.suggestion_ordering); mSuggestionsChecks = new SuggestionsChecks(getContext()); if (DEBUG_TIMING) Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime) + " ms"); }
会new一个SummaryLoader 它的构造方法主要做了这几件事:
1、创建一个Handler对象;
2、创建异步线程;
3、利用双重循环遍历每个title,然后通过异步线程处理各个tile;
public SummaryLoader(Activity activity, List categories) { mHandler = new Handler(); mWorkerThread = new HandlerThread("SummaryLoader", Process.THREAD_PRIORITY_BACKGROUND); mWorkerThread.start(); mWorker = new Worker(mWorkerThread.getLooper()); mActivity = activity; for (int i = 0; i < categories.size(); i++) { List tiles = categories.get(i).tiles; for (int j = 0; j < tiles.size(); j++) { Tile tile = tiles.get(j); mWorker.obtainMessage(Worker.MSG_GET_PROVIDER, tile).sendToTarget(); } } } private synchronized void makeProviderW(Tile tile) { SummaryProvider provider = getSummaryProvider(tile); if (provider != null) { if (DEBUG) Log.d(TAG, "Creating " + tile); mSummaryMap.put(provider, tile.intent.getComponent()); } }
可以发现最后把 SummaryProvider和 Component已键值对的形式放到了一个ArrayMap中。
这里关键看下getSummaryProvider的实现
private SummaryProvider getSummaryProvider(Tile tile) { if (!mActivity.getPackageName().equals(tile.intent.getComponent().getPackageName())) { // Not within Settings, can't load Summary directly. // TODO: Load summary indirectly. // return null; /// M: support external app dynamic summary return ExternalSummaryProvider.createExternalSummaryProvider(mActivity, this, tile); } Bundle metaData = getMetaData(tile); if (metaData == null) { if (DEBUG) Log.d(TAG, "No metadata specified for " + tile.intent.getComponent()); return null; } String clsName = metaData.getString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS); if (clsName == null) { if (DEBUG) Log.d(TAG, "No fragment specified for " + tile.intent.getComponent()); return null; } try { Class<?> cls = Class.forName(clsName); Field field = cls.getField(SUMMARY_PROVIDER_FACTORY); SummaryProviderFactory factory = (SummaryProviderFactory) field.get(null); return factory.createSummaryProvider(mActivity, this); } catch (ClassNotFoundException e) { if (DEBUG) Log.d(TAG, "Couldn't find " + clsName, e); } catch (NoSuchFieldException e) { if (DEBUG) Log.d(TAG, "Couldn't find " + SUMMARY_PROVIDER_FACTORY, e); } catch (ClassCastException e) { if (DEBUG) Log.d(TAG, "Couldn't cast " + SUMMARY_PROVIDER_FACTORY, e); } catch (IllegalAccessException e) { if (DEBUG) Log.d(TAG, "Couldn't get " + SUMMARY_PROVIDER_FACTORY, e); } return null; }
这个方法主要做了以下几件事:
1、获取MetaData;
2、获取MetaData的的META_DATA_KEY_FRAGMENT_CLASS值的值
3、根据上一步获取的字符串 通过反射来获取这个类(上一步获取的字符串形式就是“com.android.settings.fuelgauge.PowerUsageSummary” 这样的)
4、通过上步获取的类获取类中的SUMMARY_PROVIDER_FACTORY这个属性
5、返回类中的SummaryProvider对象。
看第三步可以知道这里获取的就是主界面的各个选项,这里以PowerUsageSummary为例进去看下
public class PowerUsageSummary extends PowerUsageBase {...private static class SummaryProvider implements SummaryLoader.SummaryProvider { private final Context mContext; private final SummaryLoader mLoader; private SummaryProvider(Context context, SummaryLoader loader) { mContext = context; mLoader = loader; } @Override public void setListening(boolean listening) { if (listening) { // TODO: Listen. BatteryInfo.getBatteryInfo(mContext, new BatteryInfo.Callback() { @Override public void onBatteryInfoLoaded(BatteryInfo info) { mLoader.setSummary(SummaryProvider.this, "("+(int)BatteryCapcityValue+"mAh)"+info.mChargeLabelString);//add by linyu.li for battery show 20170724 } }); } } } public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY = new SummaryLoader.SummaryProviderFactory() { @Override public SummaryLoader.SummaryProvider createSummaryProvider(Activity activity, SummaryLoader summaryLoader) { return new SummaryProvider(activity, summaryLoader); } };}
所以主界面的每个选项都必须要实现SummaryProvider 和SummaryLoader.SummaryProviderFactory这两个类才能正确的显示Summary
参考文章:http://blog.csdn.net/a771642/article/details/70284335
更多相关文章
- android悬浮按钮(Floating action button)的两种实现方法
- Android的界面提醒之对话框Dialog
- android adb启动失败问题 adb server is out of date. killing..
- 学习Android界面设计的超级利器HierarchyView.bat
- Android上webview界面切换动画效果
- 启动一个没有界面的Activity
- Android(安卓)手机小闹钟
- Android(安卓)实战 (一) Remote Service,Thread,Handler,Broadcast
- Android源码repo init及repo sync小记