Я не понимаю, почему происходит это ClassCastException - PullRequest
24 голосов
/ 05 января 2012
// Application ...
Intent i = new Intent();
i.putExtra(EXTRA_FILE_UPLOAD_URIS, mGalleryAdapter.getItems()); 

Uri[] getItems() { return mItems; }

// Service ...
intent.getParcelableArrayExtra(EXTRA_FILE_UPLOAD_URIS); //works, returns Parcelable[]
Uri[] uris = (Uri[])intent.getParcelableArrayExtra(EXTRA_FILE_UPLOAD_URIS);
// ... Breaks with ClassCastException

Почему приведение к Uri[] прерывается, когда Uri равно Parcelable?

Ответы [ 5 ]

28 голосов
/ 14 февраля 2013

Используйте этот метод, он работает для меня.

Parcelable[] ps = getIntent().getParcelableArrayExtra();
Uri[] uri = new Uri[ps.length];
System.arraycopy(ps, 0, uri, 0, ps.length);
22 голосов
/ 05 января 2012

К сожалению, в Java нет способа разыгрывать подобные массивы. Вам нужно будет выполнить итерацию вашего массива и привести каждый объект отдельно.

Причиной этого является тип Safety, JVM просто не может гарантировать, что содержимое вашего массива может быть приведено к Uri, без необходимости итерировать по ним, поэтому вам нужно итерировать их и приводить их по отдельности.

В основном, поскольку Parcelable может наследоваться другими объектами, нет гарантии, что массив содержит только Uri объектов. Однако приведение к супертипу сработает с тех пор, как безопасность типов будет в порядке.

10 голосов
/ 19 ноября 2013

Массивы имеют полиморфное поведение - только универсальные типы не имеют.

То есть, если Uri реализует Parcelable, то

Вы МОЖЕТЕ сказать:

Parcelable[] pa = new Uri[size];
Uri[] ua = (Uri[]) pa;

Вы НЕ МОЖЕТЕ сказать:

List<Parcelable> pl = new ArrayList<Uri>();

Как видите, мы можем привести pa обратно к Uri[]. Тогда в чем проблема? Это ClassCastException происходит, когда ваше приложение убито, а затем сохраненный массив воссоздается. Когда он воссоздается, среда выполнения не знает, какой это был массив (Uri[]), поэтому он просто создает Parcelable[] и помещает в него элементы. Следовательно, ClassCastException, когда вы пытаетесь привести его к Uri[].

Обратите внимание, что исключение не возникает (теоретически), когда процесс не прерывается и первоначально созданный массив (Uri[]) повторно используется между раундами сохранения / восстановления состояния. Например, когда вы меняете ориентацию.

Я просто хотел уточнить, ПОЧЕМУ это произошло. Если вы хотите, чтобы решение @solo предоставило достойное решение.

Приветствия

0 голосов
/ 14 июня 2019

https://stackoverflow.com/a/8745966/72437 и https://stackoverflow.com/a/20073367/72437 имеют четкое объяснение того, почему происходит такой сбой.

https://stackoverflow.com/a/14866690/72437 также есть пример того, как мы можем обойти это.

Я хотел бы привести примеры кода, чтобы помочь лучше понять.

Позвольте мне продемонстрировать пример того, почему такой инцидент иногда не срабатывает.

Пример, демонстрирующий, почему происходит такой сбой

package javaapplication12;

/**
 *
 * @author yccheok
 */
public class JavaApplication12 {

    public static class Parcelable {

    }

    public static class Uri extends Parcelable {

    }

    public static Parcelable[] getParcelableArrayExtraDuringLowMemoryRestoration() {    
        // The Android system has no way to know it needs to create Uri[],
        // during low memory restoration process.

        Parcelable[] parcelables = new Parcelable[3];

        for (int i=0; i<parcelables.length; i++) {
            parcelables[i] = new Uri();
        }

        return parcelables;
    }

    public static Parcelable[] getParcelableArrayExtra() {        
        // The Android system has enough information that it needs to create Uri[]

        Uri[] temp = new Uri[3];
        for (int i=0; i<temp.length; i++) {
            temp[i] = new Uri();
        }
        Parcelable[] parcelables = temp;
        return parcelables;
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // OK
        {
            // true
            System.out.println(getParcelableArrayExtra() instanceof Uri[]);

            Uri[] uris = (Uri[])getParcelableArrayExtra();
            for (Uri uri : uris) {
                System.out.println(uri);
            }
        }

        // Crash!
        {
            // false
            System.out.println(getParcelableArrayExtraDuringLowMemoryRestoration() instanceof Uri[]);

            // ClassCastException.
            Uri[] uris = (Uri[])getParcelableArrayExtraDuringLowMemoryRestoration();         
            for (Uri uri : uris) {
                System.out.println(uri);
            }
        }
    }    
}

Пример, демонстрирующий, как мы можем это исправить

package javaapplication12;

/**
 *
 * @author yccheok
 */
public class JavaApplication12 {

    public static class Parcelable {

    }

    public static class Uri extends Parcelable {

    }

    public static Parcelable[] getParcelableArrayExtraDuringLowMemoryRestoration() {    
        // The Android system has no way to know it needs to create Uri[],
        // during low memory restoration process.
        Parcelable[] parcelables = new Parcelable[3];

        for (int i=0; i<parcelables.length; i++) {
            parcelables[i] = new Uri();
        }

        return parcelables;
    }

    public static Parcelable[] getParcelableArrayExtra() {        
        // The Android system has enough information that it needs to create Uri[]
        Uri[] temp = new Uri[3];
        for (int i=0; i<temp.length; i++) {
            temp[i] = new Uri();
        }
        Parcelable[] parcelables = temp;
        return parcelables;
    }

    private static Uri[] safeCastToUris(Parcelable[] parcelables) {
        if (parcelables instanceof Uri[]) {
            return (Uri[])parcelables;
        }
        int length = parcelables.length;
        Uri[] uris = new Uri[length];
        System.arraycopy(parcelables, 0, uris, 0, length);
        return uris;
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // OK
        {
            Uri[] uris = safeCastToUris(getParcelableArrayExtra());
            for (Uri uri : uris) {
                System.out.println(uri);
            }
        }

        // OK too!
        {
            Uri[] uris = safeCastToUris(getParcelableArrayExtraDuringLowMemoryRestoration());            
            for (Uri uri : uris) {
                System.out.println(uri);
            }
        }
    }    
}
0 голосов
/ 05 января 2012

Я думаю, что происходит что-то вроде следующего:

class Parent { }

class MaleParent extends Parent { }

class FemaleParent extends Parent { }

Если сценарий такой, как указано выше, то во время выполнения произойдет сбой следующего:

Parent[] parents = new FemaleParent[]{};
MaleParent[] maleParents = (MaleParent[]) parents;

Что-то следующее не даетподнять исключение:

Parent[] parents = new MaleParent[]{};
MaleParent[] maleParents = (MaleParent[]) parents;
...