// 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
会中断?
答案 0 :(得分:28)
使用此方法,它适合我。
Parcelable[] ps = getIntent().getParcelableArrayExtra();
Uri[] uri = new Uri[ps.length];
System.arraycopy(ps, 0, uri, 0, ps.length);
答案 1 :(得分:21)
不幸的是,Java
无法对数组进行强制转换。您将不得不迭代您的数组并单独转换每个对象。
原因是类型为Safety,JVM
无法确保数组的内容可以转换为Uri,而不必通过它们进行迭代,这就是为什么你必须迭代它们并抛出它们个别。
基本上因为Parcelable
可以被其他对象继承,所以不能保证数组只包含Uri
个对象。但是,转换为超类型将起作用,因为类型安全性是可以的。
答案 2 :(得分: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提供一个体面的解决方案。
干杯
答案 3 :(得分: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;
答案 4 :(得分:0)
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);
}
}
}
}