原因是这样,我gradle插件升级到3.1.3.然后在launcher3里面加了一个app的过滤,为了不让这个app显示出来而已,简简单单的一行代码,把数据库删了重新运行一遍,结果桌面的widget不见了。。。不见了,于是第一步把代码回退,还是没有出现。于是有了这篇文章记录下整个分析过程。
launcher加载
launcher第一次加载读取的xml的资源default_workspace.xml,读取完之后保存在数据库,后面有了数据库就不会去读xml资源了。
所以想法一:数据库是否有这个widget,我把数据库pull下来之后发现没有。--也就是说读取xml这边就出问题了。
读取xml方法:
在LauncherProvider.loadFavorites()中,这个方法主要是加载favorite。
private int loadFavorites(SQLiteDatabase db, int workspaceResourceId) {
Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
ContentValues values = new ContentValues();
if (LOGD)
Log.v(TAG, String.format("Loading favorites from resid=0x%08x", workspaceResourceId));
PackageManager packageManager = mContext.getPackageManager();
int i = 0;
try {
//读取xml资源
XmlResourceParser parser = mContext.getResources().getXml(workspaceResourceId);
AttributeSet attrs = Xml.asAttributeSet(parser);
beginDocument(parser, TAG_FAVORITES);
final int depth = parser.getDepth();
int type;
//找到标签元素开始,将其一一对应
//这个next相当于指针,指向下一位
while (((type = parser.next()) != XmlPullParser.END_TAG ||
parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
if (type != XmlPullParser.START_TAG) {
continue;
}
boolean added = false;
final String name = parser.getName();
//如果标签是
if (TAG_INCLUDE.equals(name)) {
final TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.Include);
final int resId = a.getResourceId(R.styleable.Include_workspace, 0);
if (LOGD)
Log.v(TAG, String.format(("%" + (2 * (depth + 1)) + "s"),
"", resId));
//遍历的资源
if (resId != 0 && resId != workspaceResourceId) {
// recursively load some more favorites, why not?
i += loadFavorites(db, resId);
added = false;
} else {
Log.w(TAG, String.format("Skipping ", resId));
}
a.recycle();
if (LOGD)
Log.v(TAG, String.format(("%" + (2 * (depth + 1)) + "s "), ""));
continue;
}
//这个和自定义属性是一样的,通过tpyeArray找到对应的属性
TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.Favorite);
for (int ii =0;ii< attrs.getAttributeCount();ii++){
Log.d(TAG, "loadFavorites: maliimali attr"+attrs.getAttributeName(ii)+" :"+attrs.getAttributeValue(ii));
}
long container = LauncherSettings.Favorites.CONTAINER_DESKTOP;
if (a.hasValue(R.styleable.Favorite_container)) {
container = Long.valueOf(a.getString(R.styleable.Favorite_container));
}
//获取属性值
String screen = a.getString(R.styleable.Favorite_screen);
String x = a.getString(R.styleable.Favorite_x);
String y = a.getString(R.styleable.Favorite_y);
values.clear();
//将属性值保存在values里
values.put(LauncherSettings.Favorites.CONTAINER, container);
values.put(LauncherSettings.Favorites.SCREEN, screen);
values.put(LauncherSettings.Favorites.CELLX, x);
values.put(LauncherSettings.Favorites.CELLY, y);
if (LOGD) {
final String title = a.getString(R.styleable.Favorite_title);
final String pkg = a.getString(R.styleable.Favorite_packageName);
final String something = title != null ? title : pkg;
Log.d(TAG, "maliimali loadFavorites: name = "+name+" container = "+container +"screen = "+screen +" x= "+x+" y = "+y+" something = "+something );
Log.v(TAG, String.format(
("%" + (2 * (depth + 1)) + "s<%s%s c=%d s=%s x=%s y=%s>"),
"", name,
(something == null ? "" : (" \"" + something + "\"")),
container, screen, x, y));
}
//对应标签添加不同类型的内容,将其保存在数据库里
if (TAG_FAVORITE.equals(name)) {
long id = addAppShortcut(db, values, a, packageManager, intent);
added = id >= 0;
} else if (TAG_SEARCH.equals(name)) {
added = addSearchWidget(db, values);
} else if (TAG_CLOCK.equals(name)) {
added = addClockWidget(db, values);
} else if (TAG_APPWIDGET.equals(name)) {
added = addAppWidget(parser, attrs, type, db, values, a, packageManager);
} else if (TAG_SHORTCUT.equals(name)) {
long id = addUriShortcut(db, values, a);
added = id >= 0;
} else if (TAG_FOLDER.equals(name)) {
String title;
int titleResId = a.getResourceId(R.styleable.Favorite_title, -1);
if (titleResId != -1) {
title = mContext.getResources().getString(titleResId);
} else {
title = mContext.getResources().getString(R.string.folder_name);
}
values.put(LauncherSettings.Favorites.TITLE, title);
long folderId = addFolder(db, values);
added = folderId >= 0;
ArrayList folderItems = new ArrayList();
int folderDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_TAG ||
parser.getDepth() > folderDepth) {
if (type != XmlPullParser.START_TAG) {
continue;
}
final String folder_item_name = parser.getName();
TypedArray ar = mContext.obtainStyledAttributes(attrs,
R.styleable.Favorite);
values.clear();
values.put(LauncherSettings.Favorites.CONTAINER, folderId);
if (LOGD) {
final String pkg = ar.getString(R.styleable.Favorite_packageName);
final String uri = ar.getString(R.styleable.Favorite_uri);
Log.v(TAG, String.format(("%" + (2 * (folderDepth + 1)) + "s<%s \"%s\">"), "",
folder_item_name, uri != null ? uri : pkg));
}
if (TAG_FAVORITE.equals(folder_item_name) && folderId >= 0) {
long id =
addAppShortcut(db, values, ar, packageManager, intent);
if (id >= 0) {
folderItems.add(id);
}
} else if (TAG_SHORTCUT.equals(folder_item_name) && folderId >= 0) {
long id = addUriShortcut(db, values, ar);
if (id >= 0) {
folderItems.add(id);
}
} else {
throw new RuntimeException("Folders can " +
"contain only shortcuts");
}
ar.recycle();
}
// We can only have folders with >= 2 items, so we need to remove the
// folder and clean up if less than 2 items were included, or some
// failed to add, and less than 2 were actually added
if (folderItems.size() < 2 && folderId >= 0) {
// We just delete the folder and any items that made it
deleteId(db, folderId);
if (!folderItems.isEmpty()) {
deleteId(db, folderItems.get(0));
}
added = false;
}
}
if (added) i++;
a.recycle();
}
} catch (XmlPullParserException e) {
Log.w(TAG, "Got exception parsing favorites.", e);
} catch (IOException e) {
Log.w(TAG, "Got exception parsing favorites.", e);
} catch (RuntimeException e) {
Log.w(TAG, "Got exception parsing favorites.", e);
}
// Update the max item id after we have loaded the database
if (mMaxItemId == -1) {
mMaxItemId = initializeMaxItemId(db);
}
return i;
}
打印log显示传入xml好端端的,通过TypeArray读取出来就为null了,真的匪夷所思。
06-18 16:24:22.711 13793-13793/com.android.launcher3 D/TestDeskClock: loadFavorites: maliimali attr className :com.android.alarmclock.DigitalAppWidgetProvider
06-18 16:24:22.711 13793-13793/com.android.launcher3 D/TestDeskClock: loadFavorites: maliimali attr packageName :com.android.deskclock
06-18 16:24:22.711 13793-13793/com.android.launcher3 D/TestDeskClock: loadFavorites: maliimali attr screen :1
06-18 16:24:22.711 13793-13793/com.android.launcher3 D/TestDeskClock: loadFavorites: maliimali attr spanX :3
06-18 16:24:22.711 13793-13793/com.android.launcher3 D/TestDeskClock: loadFavorites: maliimali attr spanY :1
06-18 16:24:22.711 13793-13793/com.android.launcher3 D/TestDeskClock: loadFavorites: maliimali attr x :0
06-18 16:24:22.711 13793-13793/com.android.launcher3 D/TestDeskClock: loadFavorites: maliimali attr y :0
06-18 16:24:22.712 13793-13793/com.android.launcher3 D/TestDeskClock: loadFavorites: type = 2 parserName = appwidget attributeSet = 7
06-18 16:24:22.712 13793-13793/com.android.launcher3 D/TestDeskClock: loadFavorites: maliimali parser className :com.android.alarmclock.DigitalAppWidgetProvider
06-18 16:24:22.712 13793-13793/com.android.launcher3 D/TestDeskClock: loadFavorites: maliimali parser packageName :com.android.deskclock
06-18 16:24:22.712 13793-13793/com.android.launcher3 D/TestDeskClock: loadFavorites: maliimali parser screen :1
06-18 16:24:22.712 13793-13793/com.android.launcher3 D/TestDeskClock: loadFavorites: maliimali parser spanX :3
06-18 16:24:22.712 13793-13793/com.android.launcher3 D/TestDeskClock: loadFavorites: maliimali parser spanY :1
06-18 16:24:22.712 13793-13793/com.android.launcher3 D/TestDeskClock: loadFavorites: maliimali parser x :0
06-18 16:24:22.712 13793-13793/com.android.launcher3 D/TestDeskClock: loadFavorites: maliimali parser y :0
06-18 16:24:22.712 13793-13793/com.android.launcher3 D/TestDeskClock: maliimali loadFavorites: name = appwidget container = -100screen = null x= null y = null something = null
最后走了九九八十一关之后,就把xml里面的命名空间指定的包名给删了,没错就是这个
xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3"
运行,他喵的竟然可以了。
由于前面耗费了太多仙气,我有点体力不支,到嘴的答案不想钻了,毕竟问题已经改了。还请有人知道的话,悄咪咪的告诉我一声,不胜感激 感激涕零 。
猜测:这个应该和gralde插件有关,插件2.+的时候没有遇到过这个问题,就是最近升级了插件才出现的。
这个可能有解答
In Gradle projects, the actual package used in the final APK can vary; for example,you can add a .debug package suffix in one version and not the other. Therefore, you should not hardcode the application package in the resource; instead, use the special namespace http://schemas.android.com/apk/res-auto which will cause the tools to figure out the right namespace for the resource regardless of the actual package used during the build.