Android5.0 Lollipop Setting启动分析

1.Android5.0和前版本的Setting实现方式有区别,需要看较早版本的请戳http://blog.csdn.net/wangjinyu501/article/details/22077803
2.本文主要是对Setting的启动进行大致分析

1.总概况

本文只分析启动过程

2.Settings初始化流程

首先根据manifest文件找出最先启动的activity:Settings。该类具体代码如下:
public class Settings extends SettingsActivity {

    /*
    * Settings subclasses for launching independently.
    */
    public static class BluetoothSettingsActivity extends SettingsActivity { /* empty */ }
    public static class WirelessSettingsActivity extends SettingsActivity { /* empty */ }
    public static class SimSettingsActivity extends SettingsActivity { /* empty */ }
    public static class AppOpsSummaryActivity extends SettingsActivity {
        @Override
        public boolean isValidFragment(String className) {
            if (AppOpsSummary.class.getName().equals(className)) {
                return true;
            }
            return super.isValidFragment(className);
            }
    }
    public static class StorageUseActivity extends SettingsActivity { /* empty */ }
    public static class OtherSoundSettingsActivity extends SettingsActivity { /* empty */ }
    public static class QuickLaunchSettingsActivity extends SettingsActivity { /* empty */ }

    public static class TopLevelSettings extends SettingsActivity { /* empty */ }
    public static class ApnSettingsActivity extends SettingsActivity { /* empty */ }
}


可以看出Setting类主要是继承了SettingsActivity,然后创建了很多的内部类。直接转到SettingsActivity。既然是Activity直奔onCreate方法。
getMetaData();//此函数在初始化时会直接返回

mIsShowingDashboard = className.equals(Settings.class.getName());//此时className和Settings.class一致,为true;

 setContentView(mIsShowingDashboard   ?  R.layout.settings_main_dashboard : R.layout.settings_main_prefs);  

   
终于加载xml文件了,可知本次加载的是 R.layout.settings_main_dashboard,该xml文件代码如下:




       除了一个FrameLayout什么都没有,猜测setting的很多设置项就是放在了这个id为main_content的FrameLayout中显示的。继续onCreate方法
		mDisplayHomeAsUpEnabled = false;
                mDisplaySearch = true;
                mInitialTitleResId = R.string.dashboard_title;// Settings
                switchToFragment(DashboardSummary.class.getName(), null, false, false,mInitialTitleResId, mInitialTitle, false);


重点在 switchToFragment这个函数,猜测是将一个Fragment放在前文提到的id为main_content的FrameLayout中。

private Fragment switchToFragment(String fragmentName, Bundle args, boolean validate,
            boolean addToBackStack, int titleResId, CharSequence title, boolean withTransition) {
        if (validate && !isValidFragment(fragmentName)) {
            throw new IllegalArgumentException("Invalid fragment for this activity: "
                    + fragmentName);
        }
        Fragment f = Fragment.instantiate(this, fragmentName, args);//通过静态方法实例化一个fragment
        FragmentTransaction transaction = getFragmentManager().beginTransaction();//获取fragment操作集合
        transaction.replace(R.id.main_content, f);//将原容器中的内容替换为f
        if (withTransition) {
            TransitionManager.beginDelayedTransition(mContent);
        }
        if (addToBackStack) {
        	//在commit()方法之前,你可以调用addToBackStack(),把这个transaction加入back stack中去,这样按返回键时会出现被替换的fragment
            transaction.addToBackStack(SettingsActivity.BACK_STACK_PREFS);
        }
        if (titleResId > 0) {
            transaction.setBreadCrumbTitle(titleResId);
        } else if (title != null) {
            transaction.setBreadCrumbTitle(title);
        }
        transaction.commitAllowingStateLoss();
        getFragmentManager().executePendingTransactions();//调用commit()方法并不能立即执行transaction中包含的改变动作,commit()方法把transaction加入activity的UI线程队列中。

      // 但是,如果觉得有必要的话,可以调用executePendingTransactions()方法来立即执行commit()提供的transaction。
        return f;
    }
上述过程较为简单,核心就一句代码 transaction.replace(R.id.main_content, f),这句就是将f这个fragment放入id为main_content的FrameLayout中。那现在问题又来了,放入的这个名为 DashboardSummary的fragment又是什么呢?下面进入 DashboardSummary的分析。既然是fragment,抓住主要的几个方法就好了。
先看onCreateView:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        mLayoutInflater = inflater;
        final View rootView = inflater.inflate(R.layout.dashboard, container, false);
        mDashboard = (ViewGroup) rootView.findViewById(R.id.dashboard_container);
      return rootView;
    }

就是加载一个R.layout.dashboard然后找出其中的dashboard_container。那看看这个dashboard是什么



        

也很简单,就是一个id为dashboard_container的LinearLayout,猜测这个dashboard_container为真正放置设置项的地方。既然onCreateView中没有,就到onResume中去找。
 public void onResume() {
        super.onResume();
        sendRebuildUI();
        final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
        filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
        filter.addDataScheme("package");
        getActivity().registerReceiver(mHomePackageReceiver, filter);
    }

进入sendRebuildUI
private void sendRebuildUI() {
        if (!mHandler.hasMessages(MSG_REBUILD_UI)) {
            mHandler.sendEmptyMessage(MSG_REBUILD_UI);
        }
    }
发送一个MSG_REBUILD_UI的消息;如何处理呢?
		switch (msg.what) {
                		case MSG_REBUILD_UI: {
                 		   final Context context = getActivity();
                 		   rebuildUI(context);
               		 } break;
调用rebuildUI方法:
 private void rebuildUI(Context context) {
        if (!isAdded()) {
            Log.w(LOG_TAG, "Cannot build the DashboardSummary UI yet as the Fragment is not added");
            return;
        }
        long start = System.currentTimeMillis();
        final Resources res = getResources();
        mDashboard.removeAllViews();

        List categories =
                ((SettingsActivity) context).getDashboardCategories(true);//非常重要的一句,获取DashboardCategory
        final int count = categories.size();
        for (int n = 0; n < count; n++) {
            DashboardCategory category = categories.get(n);
            View categoryView = mLayoutInflater.inflate(R.layout.dashboard_category, mDashboard,
                    false);
            TextView categoryLabel = (TextView) categoryView.findViewById(R.id.category_title);
            categoryLabel.setText(category.getTitle(res));
            ViewGroup categoryContent =
                    (ViewGroup) categoryView.findViewById(R.id.category_content);
            final int tilesCount = category.getTilesCount();
            for (int i = 0; i < tilesCount; i++) {
                DashboardTile tile = category.getTile(i);
                DashboardTileView tileView = new DashboardTileView(context);
                updateTileView(context, res, tile, tileView.getImageView(),
                        tileView.getTitleTextView(), tileView.getStatusTextView());
                tileView.setTile(tile);
                categoryContent.addView(tileView);
            }

            // Add the category
            mDashboard.addView(categoryView);
        }
        long delta = System.currentTimeMillis() - start;
        Log.d(LOG_TAG, "rebuildUI took: " + delta + " ms");
    }
这段代码就是加载设置界面的:将每一个DashboardCategory取出,并且找出其中包含的DashboardTile形成DashboardTileView,最后显示在界面。
但是到底加进去的是什么呢?
秘密在getDashboardCategories()这里,经过一系列调用后,会调用 loadCategoriesFromResource(R.xml.dashboard_categories, categories);
而dashboard_categories:


    
    

        
        

        
        

        
        

        
        

        
        
            
        

        
        

    

    
    

        
        

        
        

        
        

        
        

        
        

        
        

        
        

        
        

        
        
            
        

    
每个dashboard-tile就是一个preference,点击后就会转到对应的fragment。


总结就是:activity先加载一个空的layout,其中有FrameLayout,然后将一个fragment放进去,在fragment中也是先加载了一个仅有一个LinearLayout的layout,接着在这个LinearLayout中加载转化的对象,形成设置的初始界面,如下图:


 






你可能感兴趣的:(Android5.0 Lollipop Setting启动分析)