Android Launcher7.0首次數據加載邏輯

    

Launcher3簡介

  Laucnher3採用mv模式。 數據層爲LauncherModel,採用異步加載方式讀寫數據。界面層爲Launcher

(1~7     )       準備工作

(8~12   )      工作線程sWorkThread 執行任務LoadTask

(11~18 )      找到適配的xml配置文件

(17~ 27)      解析xml數據,存入到workScreens  favorites數據庫


解析XML代碼分析

解析各個標籤Google採用了策略模式,各個節點都需要解析,但是隻是解析方法不同,Google將解析邏輯抽調出來,採用策略模式,降低耦合性。

21
(1)拿到根據屏幕尺寸匹配出來的default_workspace_*x*.xml文件生成解析器XmlResourceParser
(2)得到各個節點解析器對象集合
(3)循環調用parseAndAddNode開始解析節點

protected int parseLayout(int layoutId, ArrayList<Long> screenIds)
            throws XmlPullParserException, IOException {
        XmlResourceParser parser = mSourceRes.getXml(layoutId);
        beginDocument(parser, mRootTag);
        final int depth = parser.getDepth();
        int type;
        HashMap<String, TagParser> tagParserMap = getLayoutElementsMap();
        int count = 0;


        while (((type = parser.next()) != XmlPullParser.END_TAG ||
                parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
            if (type != XmlPullParser.START_TAG) {
                continue;
            }
            count += parseAndAddNode(parser, tagParserMap, screenIds);
        }
        return count;
}

22

(1)得到<include>節點標籤名,拿到dw_phone_hotseat.xml id

(2)遞歸調用方法parseLayout 去解析 dw_phone_hotseat.xml

(3)解析container,screen屬性存入到contentValues裏面

(4)解析x,y屬性存入到contentValues裏面

(5)得到<resolve>節點標籤名,去map中得到ResolveParser對象

(6)存入screenId

    protected int parseAndAddNode(
            XmlResourceParser parser,
            HashMap<String, TagParser> tagParserMap,
            ArrayList<Long> screenIds)
                    throws XmlPullParserException, IOException {
        if (TAG_INCLUDE.equals(parser.getName())) {
            final int resId = getAttributeResourceValue(parser, ATTR_WORKSPACE, 0);
            if (resId != 0) {
                // recursively load some more favorites, why not?
                return parseLayout(resId, screenIds);
            } else {
                return 0;
            }
        }

        mValues.clear();
        parseContainerAndScreen(parser, mTemp);

        final long container = mTemp[0];
        final long screenId = mTemp[1];

        mValues.put(Favorites.CONTAINER, container);
        mValues.put(Favorites.SCREEN, screenId);

        mValues.put(Favorites.CELLX,
                convertToDistanceFromEnd(getAttributeValue(parser, ATTR_X), mColumnCount));
        mValues.put(Favorites.CELLY,
                convertToDistanceFromEnd(getAttributeValue(parser, ATTR_Y), mRowCount));

        TagParser tagParser = tagParserMap.get(parser.getName());
        if (tagParser == null) {
            if (LOGD) Log.d(TAG, "Ignoring unknown element tag: " + parser.getName());
            return 0;
        }
        long newElementId = tagParser.parseAndAdd(parser);
        if (newElementId >= 0) {
            // Keep track of the set of screens which need to be added to the db.
            if (!screenIds.contains(screenId) &&
                    container == Favorites.CONTAINER_DESKTOP) {
                screenIds.add(screenId);
            }
            return 1;
        }
        return 0;
    }

24

(1)循環調用對象AppShortcutWithUriParser解析節點

protected class ResolveParser implements TagParser {

        private final AppShortcutWithUriParser mChildParser = new AppShortcutWithUriParser();

        @Override
        public long parseAndAdd(XmlResourceParser parser) throws XmlPullParserException,
                IOException {
            final int groupDepth = parser.getDepth();
            int type;
            long addedId = -1;
            while ((type = parser.next()) != XmlPullParser.END_TAG ||
                    parser.getDepth() > groupDepth) {
                if (type != XmlPullParser.START_TAG || addedId > -1) {
                    continue;
                }
                final String fallback_item_name = parser.getName();
                if (TAG_FAVORITE.equals(fallback_item_name)) {
                    addedId = mChildParser.parseAndAdd(parser);
                } else {
                    Log.e(TAG, "Fallback groups can contain only favorites, found "
                            + fallback_item_name);
                }
            }
            return addedId;
        }
    }

25

(1) 通過packageName,className屬性名,得到包類名

(2-1) 如果解析出來的包類名不爲空則通過包類名生成intent對象

(2-2)如果解析出來的包類名爲空則調用invalidPackageOrClass方法

(3)調用addShortcut方法存入到favorites數據庫

public long parseAndAdd(XmlResourceParser parser) {

            final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME);
            final String className = getAttributeValue(parser, ATTR_CLASS_NAME);
            if (!TextUtils.isEmpty(packageName) && !TextUtils.isEmpty(className)) {
                ActivityInfo info;
                try {
                    ComponentName cn;
                    try {
                        cn = new ComponentName(packageName, className);
                        info = mPackageManager.getActivityInfo(cn, 0);
                    } catch (PackageManager.NameNotFoundException nnfe) {
                        String[] packages = mPackageManager.currentToCanonicalPackageNames(
                                new String[] { packageName });
                        cn = new ComponentName(packages[0], className);
                        info = mPackageManager.getActivityInfo(cn, 0);
                    }
                    final Intent intent = new Intent(Intent.ACTION_MAIN, null)
                        .addCategory(Intent.CATEGORY_LAUNCHER)
                        .setComponent(cn)
                        .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                                Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);

                    return addShortcut(info.loadLabel(mPackageManager).toString(),
                            intent, Favorites.ITEM_TYPE_APPLICATION);
                } catch (PackageManager.NameNotFoundException e) {
                    Log.e(TAG, "Unable to add favorite: " + packageName + "/" + className, e);
                }
                return -1;
            } else {
                return invalidPackageOrClass(parser);
            }
        }

(1)通過uri屬性名解析uri值

(2)通過uri生成Intent值

(3)調用addShortcut方法存入到favorites數據庫

 protected long invalidPackageOrClass(XmlResourceParser parser) {
            final String uri = getAttributeValue(parser, ATTR_URI);
            if (TextUtils.isEmpty(uri)) {
                Log.e(TAG, "Skipping invalid <favorite> with no component or uri");
                return -1;
            }

            final Intent metaIntent;
            try {
                metaIntent = Intent.parseUri(uri, 0);
            } catch (URISyntaxException e) {
                Log.e(TAG, "Unable to add meta-favorite: " + uri, e);
                return -1;
            }

            ResolveInfo resolved = mPackageManager.resolveActivity(metaIntent,
                    PackageManager.MATCH_DEFAULT_ONLY);
            final List<ResolveInfo> appList = mPackageManager.queryIntentActivities(
                    metaIntent, PackageManager.MATCH_DEFAULT_ONLY);

            // Verify that the result is an app and not just the resolver dialog asking which
            // app to use.
            if (wouldLaunchResolverActivity(resolved, appList)) {
                // If only one of the results is a system app then choose that as the default.
                final ResolveInfo systemApp = getSingleSystemActivity(appList);
                if (systemApp == null) {
                    // There is no logical choice for this meta-favorite, so rather than making
                    // a bad choice just add nothing.
                    Log.w(TAG, "No preference or single system activity found for "
                            + metaIntent.toString());
                    return -1;
                }
                resolved = systemApp;
            }
            final ActivityInfo info = resolved.activityInfo;
            final Intent intent = mPackageManager.getLaunchIntentForPackage(info.packageName);
            if (intent == null) {
                return -1;
            }
            ///M: ALPS02377365,intent is different with launched from "all apps list" {@
            if ("com.android.gallery3d".equals(info.packageName)) {
                intent.setPackage(null);
            }
            /// @}
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                    Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);

            return addShortcut(info.loadLabel(mPackageManager).toString(), intent,
                    Favorites.ITEM_TYPE_APPLICATION);
        }
26

(1)將值存入到contentValues

(2)調用LauncherProvider類靜態內部類DatabaseHelper.insertAndCheck存入到數據庫

    protected long addShortcut(String title, Intent intent, int type) {
        long id = mCallback.generateNewItemId();
        mValues.put(Favorites.INTENT, intent.toUri(0));
        mValues.put(Favorites.TITLE, title);
        mValues.put(Favorites.ITEM_TYPE, type);
        mValues.put(Favorites.SPANX, 1);
        mValues.put(Favorites.SPANY, 1);
        mValues.put(Favorites._ID, id);
        if (mCallback.insertAndCheck(mDb, mValues) < 0) {
            return -1;
        } else {
            return id;
        }
    }

解析完所有的標籤存入到數據庫以後。繼續執行方法loadWorkSpace()讀取數據庫組sBgItemsIdMap,sBgWorkspaceItems,sBgAppWidgets,sBgFolders,sBgWorkspaceScreens。


       

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章