Android 7.0 Settings Summary 小记

Posted _solary

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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<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");
    

会new一个SummaryLoader 它的构造方法主要做了这几件事:
1、创建一个Handler对象;
2、创建异步线程;
3、利用双重循环遍历每个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();
            
        
    

 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 7.0 Settings Summary 小记的主要内容,如果未能解决你的问题,请参考以下文章

android 7.0中Settings新功能全面解析

Appium1.10.1+python3如何避免每次安装AppiumUnlock,appium Settings

Android 7.0都有哪些新功能 Android 7.0新特性汇总

移位操作

Android 7.0下仿7.0之前的时间框及去掉日选择框方法

Android 7.0下仿7.0之前的时间框及去掉日选择框方法