[置顶] Android N Settings实战开发(2)一级界面状态更新
2017-12-04 14:24
579 查看
Android N Settings实战开发(2)一级界面状态更新
上一篇写了N版本Settings的基本一级界面和二级界面增加。
Android N Settings实战开发(1)
第二篇就写一下N版本的Settings的一级界面状态更新。
如上图在Android7.0中增加了新的功能,一级菜单状态的动态更新。
1.尝试在AndroidManifest增加summary(不能动态显示)
加入之后会在一级菜单中显示summary可是发现不能够动态变化。看了下settings各个模块的AndroidManifest的配置 发现之后suggestion模块中加了summary,suggestion中的summary都是固定的不需要动态更新。
所以,换一种思路:自己写一个PreferenceScreen去实现,但是这样自定义的xml会和settings整体风格差距很大。而且这也不是正确的系统开发的方法
2.按照源码思路增加一级菜单的summary(可以动态更新)
前面在AndroidManifest中加入summary不能动态更新,那么就给我们提供了一种思路就是要动态加入summary
参考DisplaySettings.java的一级界面的summary
要想动态更新自定义的settings只要在在自己的类中加入以下内容就可以了
3.setSummary方法分析
通过上面的代码我们可以分不难看出实际实现的是下面这句代码中的setSummary方法
发现主要就是设置titile的summary然后通知Adapter更新,而Adapter是DashboardAdapter的实例,是设置给DashboardSummary的
进入DashboardAdapter查询
frameworks\support\v7\recyclerview\src\android\support\v7\widget
写到这里,可能还是不清楚到底是怎么运行的。实际上mAdapter.notifyChanged(tile);
是在DashboardSummary中的oncreate中
onCreate中用了
new SummaryLoader()
利用双重循环遍历每个title,然后通过异步线程处理各个tile;
综上最后回归到getSummaryProvider(Tile tile)
1、获取MetaData;
2、获取MetaData的的META_DATA_KEY_FRAGMENT_CLASS值的值
3、根据上一步获取的字符串 通过反射来获取这个类(上一步获取的字符串形式就是“com.android.settings.fuelgauge.PowerUsageSummary” 这样的)
4、通过上步获取的类获取类中的SUMMARY_PROVIDER_FACTORY这个属性
5、返回类中的SummaryProvider对象。
上一篇写了N版本Settings的基本一级界面和二级界面增加。
Android N Settings实战开发(1)
第二篇就写一下N版本的Settings的一级界面状态更新。
如上图在Android7.0中增加了新的功能,一级菜单状态的动态更新。
1.尝试在AndroidManifest增加summary(不能动态显示)
<meta-data android:name="com.android.settings.summary" android:resource="@string/zen_mode_automation_suggestion_summary" />
加入之后会在一级菜单中显示summary可是发现不能够动态变化。看了下settings各个模块的AndroidManifest的配置 发现之后suggestion模块中加了summary,suggestion中的summary都是固定的不需要动态更新。
所以,换一种思路:自己写一个PreferenceScreen去实现,但是这样自定义的xml会和settings整体风格差距很大。而且这也不是正确的系统开发的方法
2.按照源码思路增加一级菜单的summary(可以动态更新)
前面在AndroidManifest中加入summary不能动态更新,那么就给我们提供了一种思路就是要动态加入summary
参考DisplaySettings.java的一级界面的summary
要想动态更新自定义的settings只要在在自己的类中加入以下内容就可以了
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) { updateSummary(); } } private void updateSummary() { boolean auto = Settings.System.getInt(mContext.getContentResolver(), SCREEN_BRIGHTNESS_MODE, SCREEN_BRIGHTNESS_MODE_AUTOMATIC) == SCREEN_BRIGHTNESS_MODE_AUTOMATIC; mLoader.setSummary(this, mContext.getString(auto ? R.string.display_summary_on : R.string.display_summary_off)); } } 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); } }; } };
3.setSummary方法分析
通过上面的代码我们可以分不难看出实际实现的是下面这句代码中的setSummary方法
mLoader.setSummary(this, mContext.getString(auto ? R.string.display_summary_on : R.string.display_summary_off));
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的
mAdapter.notifyChanged(tile);
进入DashboardAdapter查询
public void notifyChanged(Tile tile) { notifyDataSetChanged(); }
frameworks\support\v7\recyclerview\src\android\support\v7\widget
public final void notifyDataSetChanged() { mObservable.notifyChanged(); }
public void notifyChanged() { // since onChanged() is implemented by the app, it could do anything, including // removing itself from {@link mObservers} - and that could cause problems if // an iterator is used on the ArrayList {@link mObservers}. // to avoid such problems, just march thru the list in the reverse order. for (int i = mObservers.size() - 1; i >= 0; i--) { mObservers.get(i).onChanged(); } }
写到这里,可能还是不清楚到底是怎么运行的。实际上mAdapter.notifyChanged(tile);
是在DashboardSummary中的oncreate中
@Override public void onCreate(Bundle savedInstanceState) { long startTime = System.currentTimeMillis(); super.onCreate(savedInstanceState); List<DashboardCategory> 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"); }
onCreate中用了
mSummaryLoader = new SummaryLoader(getActivity(), categories);
new SummaryLoader()
利用双重循环遍历每个title,然后通过异步线程处理各个tile;
public SummaryLoader(Activity activity, List<DashboardCategory> 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<Tile> 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(); } } } //调用makeProviderW将SummaryProvider和 Component已键值对的形式放到了一个ArrayMap 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()); } }
综上最后回归到getSummaryProvider(Tile tile)
1、获取MetaData;
2、获取MetaData的的META_DATA_KEY_FRAGMENT_CLASS值的值
3、根据上一步获取的字符串 通过反射来获取这个类(上一步获取的字符串形式就是“com.android.settings.fuelgauge.PowerUsageSummary” 这样的)
4、通过上步获取的类获取类中的SUMMARY_PROVIDER_FACTORY这个属性
5、返回类中的SummaryProvider对象。
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; }
相关文章推荐
- [置顶] Android N Settings实战开发(1)一,二级界面增加
- 手机卫士开发_setting界面和自动更新的设置
- [置顶]浅谈3年游戏开发de自学历程!(仅供参考)【2011年9月15号_更新】
- [置顶] jBPM4工作流开发实战 之 第二部分 jBPM4开发入门
- Android开发本地及网络Mp3音乐播放器(十)最近播放界面与数据保存更新
- Python开发入门与实战13-基于模板的界面
- iOS 开发实战-锁屏界面(密码解锁)
- Python开发入门与实战14-基于Extjs的界面
- [置顶] 《Android Studio开发实战 从零基础到App上线》出版后记
- 安卓开发实战之app之版本更新升级(DownloadManager和http下载)完整实现
- 跟着BOY学习开发cocos2d-x 游戏 实战篇(3)之 游戏主界面 -----武器系统---散花弹
- [置顶] iOS-发布状态界面github开源
- [置顶] 自己开发的分布式erp系统的界面设计
- 实战Unity3D开发:从认识界面到游戏demo
- 【原】让代码轻盈地飞舞——IDEA13最实用的功能,全面提升开发效率(桌面java项目开发实战)持续更新中
- 专稿:实战EJB之二 开发会话Bean(无状态会话Bean)
- 商业开发实战之VB篇视频-更新完毕
- JFinal极速开发实战教程[持续更新中~~]
- [置顶] android开发中出现的错误集(不断更新)