我得到一个奇怪的行为,我想我更需要解释而不是解决方案(虽然也欢迎解决方案!)。
以下是代码:
PackageManager pm = context.getPackageManager();
List<PackageInfo> pkgList = pm.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);
if (pkgList == null)
return null;
for (PackageInfo pkgInfo : pkgList) {
ApplicationInfo appInfo = pkgInfo.applicationInfo;
// do some stuff, doesn't modify pkgInfo or appInfo or pkgList
}
在某些情况下,我收到错误日志:
java.lang.ClassCastException:无法强制转换为android.content.pm.PackageInfo
报告为行:
for (PackageInfo pkgInfo : pkgList)
奇怪的是,ClassCastException
通常看起来像(AFAIK):
java.lang.ClassCastException: foo.bar.ClassA 无法转换为 foo.bar.ClassB
但是,我看到的错误在第一部分显示为空白。
我决定稍微研究一下,如果返回列表的函数内部输入错误的对象列表并返回它或其他东西,那么可能会发生一些事情。所以我看了一下:
ApplicationPackageManager.getInstalledPackages()
@SuppressWarnings("unchecked")
@Override
public List<PackageInfo> getInstalledPackages(int flags) {
try {
final List<PackageInfo> packageInfos = new ArrayList<PackageInfo>();
PackageInfo lastItem = null;
ParceledListSlice<PackageInfo> slice;
do {
final String lastKey = lastItem != null ? lastItem.packageName : null;
slice = mPM.getInstalledPackages(flags, lastKey);
lastItem = slice.populateList(packageInfos, PackageInfo.CREATOR);
} while (!slice.isLastSlice());
return packageInfos;
} catch (RemoteException e) {
throw new RuntimeException("Package manager has died", e);
}
}
好的,所以返回的列表是从ParceledListSlice.populateList()...
ParceledListSlice.populateList()
public T populateList(List<T> list, Creator<T> creator) {
mParcel.setDataPosition(0);
T item = null;
for (int i = 0; i < mNumItems; i++) {
item = creator.createFromParcel(mParcel);
list.add(item);
}
mParcel.recycle();
mParcel = null;
return item;
}
所以该项目是从PackageInfo.CREATOR.createFromParcel()
...
最后是creator.createFromParcel
PackageInfo
public static final Parcelable.Creator<PackageInfo> CREATOR
= new Parcelable.Creator<PackageInfo>() {
public PackageInfo createFromParcel(Parcel source) {
return new PackageInfo(source);
}
public PackageInfo[] newArray(int size) {
return new PackageInfo[size];
}
};
所以一切似乎都没问题。它正在创建ParceledListSlice
类型PackageInfo
,因此在populateList
中,它会创建一个PackageInfo
项并将其放入List
PackageInfo
,这是返回的列表。所有类型/类对我来说都很好。
所以我的问题,
我在考虑将列表作为Object
的列表并检查“instanceof
”,但我认为这不会起作用,因为它可能最终会说} p>
ClassCastException:无法转换为java.lang.Object“或其他东西。
对于如何发生这种情况的任何见解和解释都将不胜感激。
我只能猜测猜测=)
答案 0 :(得分:0)
如果您确定在此行中获得了ClassCastException
for (PackageInfo pkgInfo : pkgList)
当出现原因时 - 某种程度上pkgList
包含的值不是PackageInfo
类。我假设这是NULL
值。为什么你在ClassCast错误消息中看不到它,因为NULL对象的className
只是空字符串。
现在,如何解决这个问题 - 使用手动循环。 for aech
循环使用Iterator
,因此您无法控制每次迭代的类转换。但是如果你使用这样的代码:
for (int i = 0; i < pkgList.length; i++) {
Object pkgInfoObj = pkgList.get(i);
if (pkgInfoObj instanceof PackageInfo) {
PackageInfo pkgInfo = (PackageInfo) pkgInfoObj;
ApplicationInfo appInfo = pkgInfo.applicationInfo;
// do some stuff, doesn't modify pkgInfo or appInfo or pkgList
}
}
您将能够控制类投射。
此外,您可以抓住 ClassCastException
,只需跳过此循环步骤即可。
答案 1 :(得分:0)
这似乎是Android本身的一个问题。我发现一些针对Android的错误报告显示了类似的行为:
Issue 26644: ClassCastException and IncompatibleClassChangeError
Issue 36560: Exception in (SensorManager.java:521)
我也看过问题26644中提到的IncompatibleClassChangeError。我唯一的猜测是,这些看似不可能的异常/错误是由于一些奇怪的内存损坏或dalvik / jvm问题。似乎代码本身没有任何问题。如果其他人有更好的解释,请随意填写=)