Launcher8.0启动流程的第六步中loadworkspace的第1小步是获取数据库,在没有布局时,需要读取手机上的布局xml文件,通过第二个操作知道了到底选取哪里的xml文件,但是,手机的行列数参数是Launcher根据手机本身通过启动流程第一步获取的,在运行之前不知道,那么如何选择行列数正确的xml文件呢?
这里就涉及到一个重要的类 AutoInstallsLayout 和该类的一个方法:
AutoInstallsLayout.get(ctx, packageName, targetResources,
widgetHost, mOpenHelper);
获取AutoInstallsLayout方法,首先获取layoutName,这个名字就是xml名字。
在原生代码res/xml/ 文件夹下面有default_workspace.xml default_workspace_3x3.xml
default_workspace_4x4.xml default_workspace_5x5.xml default_workspace_5x6.xml 一共5个布局文件。
下面则是采用多个方式来获取布局xml,因为不知道xml文件的具体名字所以采用递进的方法来获取。
源码如下:
static AutoInstallsLayout get(Context context, String pkg, Resources targetRes,
AppWidgetHost appWidgetHost, LayoutParserCallback callback) {
InvariantDeviceProfile grid = LauncherAppState.getIDP(context);
String layoutName = String.format(Locale.ENGLISH, FORMATTED_LAYOUT_RES_WITH_HOSTEAT,
(int) grid.numColumns, (int) grid.numRows, (int) grid.numHotseatIcons);
int layoutId = targetRes.getIdentifier(layoutName, "xml", pkg);
// Try with only grid size
if (layoutId == 0) {
Log.d(TAG, "Formatted layout: " + layoutName
+ " not found. Trying layout without hosteat");
layoutName = String.format(Locale.ENGLISH, FORMATTED_LAYOUT_RES,
(int) grid.numColumns, (int) grid.numRows);
layoutId = targetRes.getIdentifier(layoutName, "xml", pkg);
}
// Try the default layout
if (layoutId == 0) {
Log.d(TAG, "Formatted layout: " + layoutName + " not found. Trying the default layout");
layoutId = targetRes.getIdentifier(LAYOUT_RES, "xml", pkg);
}
if (layoutId == 0) {
Log.e(TAG, "Layout definition not found in package: " + pkg);
return null;
}
return new AutoInstallsLayout(context, appWidgetHost, callback, targetRes, layoutId,
TAG_WORKSPACE);
}
首先是default_workspace_4x4x5.xml这种类型的名字,根据本手机的行数列数以及hotseat的个数来确定读取哪种布局
String layoutName = String.format(Locale.ENGLISH, FORMATTED_LAYOUT_RES_WITH_HOSTEAT,
(int) grid.numColumns, (int) grid.numRows, (int) grid.numHotseatIcons);
int layoutId = targetRes.getIdentifier(layoutName, "xml", pkg);
其次根据default_workspace_4x4.xml这种类型的名字,根据本手机的行数列数来确定读取哪种布局
layoutName = String.format(Locale.ENGLISH, FORMATTED_LAYOUT_RES,
(int) grid.numColumns, (int) grid.numRows);
layoutId = targetRes.getIdentifier(layoutName, "xml", pkg);
最后是直接默认的布局default_workspace.xml
layoutId = targetRes.getIdentifier(LAYOUT_RES, "xml", pkg);
public AutoInstallsLayout(Context context, AppWidgetHost appWidgetHost,
LayoutParserCallback callback, Resources res,
int layoutId, String rootTag) {
mContext = context;
mAppWidgetHost = appWidgetHost;
mCallback = callback;
mPackageManager = context.getPackageManager();
mValues = new ContentValues();
mRootTag = rootTag;
mSourceRes = res;
mLayoutId = layoutId;
mIdp = LauncherAppState.getIDP(context);
mRowCount = mIdp.numRows;
mColumnCount = mIdp.numColumns;
}
而后把有关信息保存在AutoInstallsLayout,返回给调用的程序。
总结,AutoInstallsLayout.get根据传入的参数,读取对应的xml文件。
实际上在运行时,我们处于没有数据库的状态,所以在loadDefaultFavoritesIfNecessary中首先是创一个数据库
mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase());
而后开始读取布局:
if ((mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(), loader) <= 0)
&& usingExternallyProvidedLayout) {
mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase());
mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(),
getDefaultLayoutParser(widgetHost));
}
If判断的内容是:mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(), loader) 将loader布局存入数据库,并返回布局有多少个屏幕。如果读取的布局一个屏幕一个图标都没有,那么会进入备用方案,
mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase());
mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(),
getDefaultLayoutParser(widgetHost));
不再使用loader而使用getDefaultLayoutParser(widgetHost),后者也对应一款xml布局文件。
到此第一小步的第三个操作完成,做好了将真正的目标xml文件导入Launcher的准备。