报错:
java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:404)
at java.util.AbstractList.add(AbstractList.java:425)
at com.xxxxxx.xxx.xxx.util.xxx$1.onResponse(xxx.java:75) // 异常代码定位点
at okhttp3.RealCall$AsyncCall.execute(RealCall.java:206)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
分析:
代码出错的位置是位于一个OkHttp的网络请求onResponse()代码块内部的一部分,部分代码如下:
@Override
public void onResponse(Call call, Response response) throws IOException {
String strData = response.body().string();
// 通过逗号分隔成List
List<String> list = Arrays.asList(strData.split(","));
list.add("000"); // 崩溃点
list.add(0, "111");
}
考虑了很多情况,包括子线程之类的都解决不了,最终感觉出问题的地方在于这个List不正经
参考:https://www.jianshu.com/p/2b113f487e5e
阅读官方文档,发现一句话:
Returns a fixed-size list backed by the specified array.
返回一个由指定数组生成的固定大小的List
尼玛坑爹啊, 人家的List本来就支持动态扩容的,偏偏这货(由Arrays.asList()方法生成的List)就是固定大小,固定大小就意味着任何改变其大小的操作(比如:add()/remove()等)都是不允许的。
为什么呢?查看Arrays.asList()源码:
@SafeVarargs
@SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
方法中的的确确生成了一个 ArrayList ,这不应该是支持动态扩容的吗?别着急,接着往下看。紧跟在 asList 方法后面,有这样一个内部类:
private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable {
private static final long serialVersionUID = -2764017481108945198L;
private final E[] a;
ArrayList(E[] array) {
a = Objects.requireNonNull(array);
}
// 省略...
}
这个内部类也叫 ArrayList ,更重要的是在这个内部类中有一个被声明为 final 的数组 a ,所有传入的元素都会被保存在这个数组 a 中。到此,谜底又揭晓了: asList() 方法返回的确实是一个 ArrayList ,但这个 ArrayList 并不是 java.util.ArrayList ,而是 java.util.Arrays 的一个内部类。这个内部类用一个 final 数组来保存元素,因此用 asList 方法产生的 ArrayList 是不可修改大小的。
解决方案:创建一个真正的List
既然由Arrays.asList()方法创建出来的List是个“不正经”的List,不能动态改变容量,如果需要改变List的大小的时候,就要创建一个"货真价实"的List:
String[] arrStr = { "Apple", "Banana", "Orange" };
List<String> myList = new ArrayList<String>(Arrays.asList(arrStr)); // 货真价实的List
myList.add("Guava");
在上面这段代码中,我们 new 了一个 java.util.ArrayList ,然后再把 asList() 方法的返回值作为构造器的参数传入,最后得到的 myList 自然就是可以动态扩容的了。