您的位置:首页 > 移动开发 > Android开发

[置顶] 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(不能动态显示)

<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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: