Android ResolveInfo Parcelable не полностью разобран

Я спотыкаюсь о то, что, как я ожидал, будет простой задачей, то есть запись объекта ResolveInfo в Parcel, а затем создание ResolveInfo из этого Parcel. К сожалению, это не так, поскольку мой код дает сбой и выдает исключение java.lang.IllegalStateException.

Вот мой код

fun failingFunction(resolveInfo:ResolveInfo){
    Log.d(TAG,"original label ${resolveInfo.loadLabel(this.packageManager)}")
    val p = Parcel.obtain()
    resolveInfo.writeToParcel(p, 0)
    val copy = ResolveInfo.CREATOR.createFromParcel(p)
    Log.d(TAG,"copy label ${copy.loadLabel(this.packageManager)}") // throws java.lang.IllegalStateException: Missing ComponentInfo!
}

Глядя на исходный код класса ResolveInfo, исключение возникает, когда нет ни одного из атрибутов ResolveInfo ActivityInfo, ServiceInfo или ProviderInfo. Поэтому я добавил журналы, чтобы проверить, не отсутствовали ли они.

fun failingFunction(resolveInfo:ResolveInfo){
    Log.d(TAG,"original activity info ${resolveInfo.activityInfo}")
    Log.d(TAG,"original service info ${resolveInfo.serviceInfo}")
    Log.d(TAG,"original provider info ${resolveInfo.providerInfo}")
    Log.d(TAG,"original label ${resolveInfo.loadLabel(this.packageManager)}")
    val p = Parcel.obtain()
    resolveInfo.writeToParcel(p, 0)
    val copy = ResolveInfo.CREATOR.createFromParcel(p)
    Log.d(TAG,"copy activity info ${copy.activityInfo}")
    Log.d(TAG,"copy service info ${copy.serviceInfo}")
    Log.d(TAG,"copy provider info ${copy.providerInfo}")
    Log.d(TAG,"copy label ${copy.loadLabel(this.packageManager)}")
}

Мой исходный объект ResolveInfo имеет ActivityInfo, а моя копия — нет. ActivityInfo реализует Parcelable, поэтому я не совсем понимаю, почему это не написано в Parcel. Согласно источнику ResolveInfo это должно быть записано в посылке и прочитано из нее:

public void writeToParcel(Parcel dest, int parcelableFlags) {
    if (activityInfo != null) {
        dest.writeInt(1);
        activityInfo.writeToParcel(dest, parcelableFlags);
    } else if (serviceInfo != null) {
        dest.writeInt(2);
        serviceInfo.writeToParcel(dest, parcelableFlags);
    } else if (providerInfo != null) {
        dest.writeInt(3);
        providerInfo.writeToParcel(dest, parcelableFlags);
    } else {
        dest.writeInt(0);
    }
    if (filter != null) {
        dest.writeInt(1);
        filter.writeToParcel(dest, parcelableFlags);
    } else {
        dest.writeInt(0);
    }
    dest.writeInt(priority);
    dest.writeInt(preferredOrder);
    dest.writeInt(match);
    dest.writeInt(specificIndex);
    dest.writeInt(labelRes);
    TextUtils.writeToParcel(nonLocalizedLabel, dest, parcelableFlags);
    dest.writeInt(icon);
    dest.writeString(resolvePackageName);
    dest.writeInt(targetUserId);
    dest.writeInt(system ? 1 : 0);
    dest.writeInt(noResourceId ? 1 : 0);
    dest.writeInt(iconResourceId);
    dest.writeInt(handleAllWebDataURI ? 1 : 0);
    dest.writeInt(isInstantAppAvailable ? 1 : 0);
}

private ResolveInfo(Parcel source) {
    activityInfo = null;
    serviceInfo = null;
    providerInfo = null;
    switch (source.readInt()) {
        case 1:
            activityInfo = ActivityInfo.CREATOR.createFromParcel(source);
            break;
        case 2:
            serviceInfo = ServiceInfo.CREATOR.createFromParcel(source);
            break;
        case 3:
            providerInfo = ProviderInfo.CREATOR.createFromParcel(source);
            break;
        default:
            Slog.w(TAG, "Missing ComponentInfo!");
            break;
    }
    if (source.readInt() != 0) {
        filter = IntentFilter.CREATOR.createFromParcel(source);
    }
    priority = source.readInt();
    preferredOrder = source.readInt();
    match = source.readInt();
    specificIndex = source.readInt();
    labelRes = source.readInt();
    nonLocalizedLabel
            = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
    icon = source.readInt();
    resolvePackageName = source.readString();
    targetUserId = source.readInt();
    system = source.readInt() != 0;
    noResourceId = source.readInt() != 0;
    iconResourceId = source.readInt();
    handleAllWebDataURI = source.readInt() != 0;
    instantAppAvailable = isInstantAppAvailable = source.readInt() != 0;
}

Подскажите кому-нибудь, почему этот вложенный Parcelable не распаковывается должным образом? Мне не хватает полезных флагов, которые я должен использовать?

Спасибо,


person Marc Poppleton    schedule 19.12.2017    source источник


Ответы (1)


Итак, я нашел, как решить проблему, это не имело ничего общего с методами Parcelable Creator, а с тем, как я использовал Parcel. Как только вы закончите писать в Parcel, вы должны вызвать setDataPosition с 0 в качестве аргумента.

Мой код теперь следующий:

fun failingFunction(resolveInfo:ResolveInfo){
    Log.d(TAG,"original label ${resolveInfo.loadLabel(this.packageManager)}")
    val p = Parcel.obtain()
    resolveInfo.writeToParcel(p, 0)
    p.setDataPosition(0)
    val copy = ResolveInfo.CREATOR.createFromParcel(p)
    Log.d(TAG,"copy label ${copy.loadLabel(this.packageManager)}") // no longer throws java.lang.IllegalStateException
}
person Marc Poppleton    schedule 20.12.2017