Android M Settings界面加载流程分析

StartUML简易分析

 


代码分析:

从Setting-AndroidManifest开始

<application android:label="@string/settings_label"

            android:icon="@mipmap/ic_launcher_settings"

            android:taskAffinity=""

            android:theme="@style/Theme.Settings"

            android:hardwareAccelerated="true"

            android:requiredForAllUsers="true"

            android:supportsRtl="true"

            android:allowBackup="false"

            android:usesCleartextTraffic="true">

        <!-- Settings -->

        <activity android:name="Settings"

                android:taskAffinity="com.android.settings"

                android:label="@string/settings_label_launcher"

                android:launchMode="singleTask">

            <intent-filter android:priority="1">

                <action android:name="android.settings.SETTINGS" />

                <category android:name="android.intent.category.DEFAULT" />

            </intent-filter>

            <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"

                android:value="true" />

        </activity>

可以看出是从Settings开始加载


Settings继承自SettingsActivity

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 TetherSettingsActivity extends SettingsActivity { /* empty */ }

    public static class VpnSettingsActivity extends SettingsActivity { /* empty */ }

    public static class DateTimeSettingsActivity extends SettingsActivity { /* empty */ }

    public static class StorageSettingsActivity extends SettingsActivity { /* empty */ }

    public static class PrivateVolumeForgetActivity extends SettingsActivity { /* empty */ }

    public static class PrivateVolumeSettingsActivity extends SettingsActivity { /* empty */ }

    public static class PublicVolumeSettingsActivity extends SettingsActivity { /* empty */ }

    public static class WifiSettingsActivity extends SettingsActivity { /* empty */ }

    public static class WifiP2pSettingsActivity extends SettingsActivity { /* empty */ }

    public static class InputMethodAndLanguageSettingsActivity extends SettingsActivity { /* empty */ }


public class SettingsActivity extends Activity

        implements PreferenceManager.OnPreferenceTreeClickListener,

        PreferenceFragment.OnPreferenceStartFragmentCallback,

        ButtonBarHandler, FragmentManager.OnBackStackChangedListener,

        SearchView.OnQueryTextListener, SearchView.OnCloseListener,

        MenuItem.OnActionExpandListener {

...

@Override

    protected void onCreate(Bundle savedState) {

        super.onCreate(savedState);

        // Should happen before any call to getIntent()

        getMetaData();

        ......

    }




//初始化第一步获取数据

    /**

     * 如获得数据成功,

     * 则表示不是直接启动设置的(比较启动的是:BluetoothSettingsActivity),

     * 则不会显示所有的设置项,只显示具体的设置项(比较蓝牙设置)。

     */

    private void getMetaData() {

        try {

            ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),

                    PackageManager.GET_META_DATA);

            if (ai == null || ai.metaData == null) return;

            mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);

        } catch (NameNotFoundException nnfe) {

            // No recovery

            Log.d(LOG_TAG, "Cannot get Metadata for: " + getComponentName().toString());

        }

    }


可以看出第一步先是进行了fragment的判断--接着onCreate其他函数往下看

...

//判断当前的类是哪个具体的类

        mIsShowingDashboard = className.equals(Settings.class.getName());


 // This is a "Sub Settings" when:

        // - this is a real SubSettings

        // - or :settings:show_fragment_as_subsetting is passed to the Intent

        //如果是通过点击桌面的设置进入,那么mIsShowingDashboard的值就为真。

        final boolean isSubSettings = this instanceof SubSettings ||

                intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SUBSETTING, false);

....

//设置进入的模块

        setContentView(mIsShowingDashboard ?

                R.layout.settings_main_dashboard : R.layout.settings_main_prefs);

....

        if (savedState != null) {

           ....

            }

         ....

        } else {

            if ((initialFragmentName != null) && !mIsShowingDashboard) {

               ....

            } else {

              //加载片段

                // No UP affordance if we are displaying the main Dashboard

                mDisplayHomeAsUpEnabled = false;

                // Show Search affordance

                mDisplaySearch = true;

                mInitialTitleResId = R.string.dashboard_title;

                /**

                 * switchToFragment()方法,目的是切换到对应的片段上(帧布局起作用了吧^ _ ^),

                 * 也就是DashboardSummary这个片段。

                 * 接下来看一下DashboardSummary.java这个类了。

                 */

                switchToFragment(DashboardSummary.class.getName(), null, false, false,

                        mInitialTitleResId, mInitialTitle, false);

            }

        }

 

关键方法...进行了Fragment界面加载-->跳转到DashboardSummary.class查看


根据上诉代码分析...大致布局可以理解为如下

 

 

---实际调用了的布局自上而下依次是---

R.layout.settings_main_dashboard

R.layout.dashboard

R.layout.dashboard_category

DashboardTile--framelayout


根据如上分析--大致如下

switchToFragment(DashboardSummary.class.getName(), null, false, false,

                        mInitialTitleResId, mInitialTitle, false);


public class DashboardSummary extends InstrumentedFragment 


    @Override

    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;

    }

紧接着查看onResume方法

    @Override

    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);

    }

private void sendRebuildUI() {

        if (!mHandler.hasMessages(MSG_REBUILD_UI)) {

            mHandler.sendEmptyMessage(MSG_REBUILD_UI);

        }

    }

    private static final int MSG_REBUILD_UI = 1;

    private Handler mHandler = new Handler() {

        @Override

        public void handleMessage(Message msg) {

            switch (msg.what) {

                case MSG_REBUILD_UI: {

                    final Context context = getActivity();

                    rebuildUI(context);

                } break;

            }

        }

    };

下面是布局进行动态加在的方法

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();

       

        //加在UI之前  先加在数据

        List<DashboardCategory> categories =

                ((SettingsActivity) context).getDashboardCategories(true);

        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");

    }

中间调用了一次SettingsActivity中解析XML数据的方法

 public List<DashboardCategory> getDashboardCategories(boolean forceRefresh) {

        if (forceRefresh || mCategories.size() == 0) {

          //更新数据--xml解析

            buildDashboardCategories(mCategories);

        }

        return mCategories;

    }

 

 

 

对应ID看对应代码,这样才是最方便的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时代我西

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值