Я не понимаю, почему это 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
?
Ответы
Ответ 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);
}
}
}
}