Подтвердить что ты не робот

Я не понимаю, почему это ClassCastException происходит

// 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?

4b9b3361

Ответ 1

К сожалению, для массивов в Java нет способа сделать это для массивов. Вам придется перебирать массив и бросать каждый объект по отдельности.

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

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

Ответ 2

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

Parcelable[] ps = getIntent().getParcelableArrayExtra();
Uri[] uri = new Uri[ps.length];
System.arraycopy(ps, 0, uri, 0, ps.length);

Ответ 3

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

То есть, если 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 предоставило достойное решение.

ура

Ответ 4

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

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;

Ответ 5

fooobar.com/info/225146/... и fooobar.com/info/225146/... имеют подробное объяснение того, почему происходит такой сбой.

fooobar.com/info/225146/... также есть пример того, как мы можем обойти это.

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

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

Пример, чтобы продемонстрировать, почему происходит такой сбой

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