天天看點

Android M Settings界面加載流程分析

StartUML簡易分析

Android M Settings界面加載流程分析

代碼分析:

從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檢視

根據上訴代碼分析...大緻布局可以了解為如下

Android M Settings界面加載流程分析

---實際調用了的布局自上而下依次是---

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;

    }
           
Android M Settings界面加載流程分析

對應ID看對應代碼,這樣才是最友善的

繼續閱讀