Android ClassCastException with blank type

hiB*_*Lee 8 java android exception classcastexception android-package-managers

I am getting a strange behavior, and I guess I'm more looking for an explanation than a solution (although solution is welcome as well!).

Here's the code:

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
} 
Run Code Online (Sandbox Code Playgroud)

And on some occasions, I am getting error logs with:

java.lang.ClassCastException: cannot be cast to android.content.pm.PackageInfo

reported for line:

for (PackageInfo pkgInfo : pkgList)
Run Code Online (Sandbox Code Playgroud)

The odd part is that, normally, ClassCastException usually look like (AFAIK):

java.lang.ClassCastException: foo.bar.ClassA cannot be cast to foo.bar.ClassB

However, the error I'm seeing is showing blank for the first part.

I decided to research a bit, and read something along the lines of it might happen if the function that's returning the list internally casted the wrong object list and returned it or something. So I looked:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

Ok, so the list that's being returned is populated from 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;
}
Run Code Online (Sandbox Code Playgroud)

So the item is being created from PackageInfo.CREATOR.createFromParcel()...

And finally the creator.createFromParcel of 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];
    }
};
Run Code Online (Sandbox Code Playgroud)

So everything seems to be ok. It's creating a ParceledListSlice of type PackageInfo, and so in populateList it's creating a PackageInfo item and putting it into a List of PackageInfo, which is the returned list. All the types/classes seem fine to me.

So my questions,

  1. how would the above ClassCastException happen?
  2. Why would it show "blank" type for the error message?
  3. And what would be a possible solution?

I was thinking of just getting the list as a list of Object and checking "instanceof", but I don't think that's gonna work either because it'll probably end up saying

ClassCastException: cannot be cast into java.lang.Object" or something.

Any insights and explanations on how this could happen would be greatly appreciated.

  1. Is Dalvik/JVM simply messing up?
  2. Is the memory being corrupted?

I could only come up wild guesses =)

Hit*_*sit 0

如果你确定你ClassCastException 正好在这条线上

for (PackageInfo pkgInfo : pkgList)
Run Code Online (Sandbox Code Playgroud)

当后面有一个原因时 - 某种程度上pkgList包含非类值PackageInfo。我认为这就是NULL价值。为什么你在 ClassCast 错误消息中看不到它,因为className对于 NULL 对象来说只是空字符串。

现在,如何解决这个问题 - 使用手动 for 循环。for each循环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
    }
}
Run Code Online (Sandbox Code Playgroud)

您将能够控制班级选角。

此外,您可以捕捉 ClassCastException并跳过此循环步骤到下一个循环步骤。