簡體   English   中英

帶有空白類型的 Android ClassCastException

[英]Android ClassCastException with blank type

我有一個奇怪的行為,我想我更多的是在尋找解釋而不是解決方案(盡管解決方案也是受歡迎的!)。

這是代碼:

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()...

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()創建的...

最后是PackageInfocreator.createFromParcel

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];
    }
};

所以一切似乎都沒問題。 它創造了ParceledListSlicePackageInfo ,因此,在populateList它創建PackageInfo項目,並把它變成一個ListPackageInfo ,這是返回的列表。 所有類型/類對我來說都很好。

所以我的問題,

  1. 上面的 ClassCastException 將如何發生?
  2. 為什么它會為錯誤消息顯示“空白”類型?
  3. 什么是可能的解決方案?

我正在考慮將列表作為Object列表並檢查“ instanceof ”,但我認為這也行不通,因為它可能最終會說

ClassCastException: cannot be cast into java.lang.Object" 之類的。

任何有關如何發生這種情況的見解和解釋將不勝感激。

  1. Dalvik/JVM 只是一團糟嗎?
  2. 內存是否損壞?

我只能胡亂猜測 =)

如果你確定你在這一行得到了ClassCastException

for (PackageInfo pkgInfo : pkgList)

當一個原因出現時 - 不知何故pkgList包含一個不是PackageInfo類的值。 我假設這是NULL值。 為什么在 ClassCast 錯誤消息中看不到它,因為 NULL 對象的className只是空字符串。

現在,如何解決這個問題 - 使用手冊 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
    }
}

您將能夠控制類鑄造。

此外,您可以捕獲ClassCastException並跳過此循環步驟到下一個循環步驟。

這似乎是 Android 本身的問題。 我發現一些針對 Android 的錯誤報告顯示了類似的行為:

問題 26644:ClassCastException 和 IncompatibleClassChangeError

問題 36560:(SensorManager.java:521) 中的異常

我還看到了問題 26644 中提到的 IncompatibleClassChangeError。 我唯一的猜測是,這些看似不可能的異常/錯誤是由於一些奇怪的內存損壞或 dalvik/jvm 問題造成的。 代碼本身似乎沒有任何問題。 如果其他人有更好的解釋,請隨時補充 =)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM