2012-01-05 2 views
23
// 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?Я не понимаю, почему это происходит ClassCastException

+0

Опубликовать stacktrace. –

+0

«Ури» унаследовал от «Parcelable» или наоборот? – fge

+0

Uri реализует Parcelable –

ответ

19

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

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

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

+0

Я думал то же самое (так как это так в C#), поэтому я искал java-массив ковариации и, похоже, поддерживался (и был дырой в типе безопасности). Являются ли мои ссылки просто устаревшими с текущей JVM? : http://www.angelikalanger.com/Articles/Papers/JavaGenerics/ArraysInJavaGenerics.htm, http://c2.com/cgi/wiki?JavaArraysBreakTypeSafety –

+1

Я думаю, что безопасность типа связана с дженериками, которая ограничена compiletime , Массивы не генерируются. Это ссылки, и вы можете делать кастинг. –

+0

правильно, но Parcelable [] был новым Uri [] в первую очередь ... так что это должно быть просто, хотя Uri является Parcelable, но Uri [] не является Parcelable [] ... –

0

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

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; 
+0

почему так много родителей? – Sayka

26

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

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

Массивы имеют полиморфное поведение - не имеют общих типов.

То есть, если 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 было достойным.

Cheers

+1

Это правильный ответ. Я наткнулся на случайное повторное появление ClassCastException, когда моя Служба попыталась передать Parcelable [] из Bundle AccountManager в Account []. Это произошло очень редко после телефонных звонков, и, наконец, вот преступник! – user1643723

Смежные вопросы