【问题标题】:HttpURLConnection failes with NullPointerException on Lollipop棒棒糖上的 HttpURLConnection 失败并出现 NullPointerException
【发布时间】:2015-05-18 08:07:38
【问题描述】:

我注意到有时,不确定在什么情况下,使用 Universal-Image-Loader (https://github.com/nostra13/Android-Universal-Image-Loader) 下载图像时,我收到以下 NullPointerException:

E/ImageLoader(27386): Attempt to invoke virtual method 'boolean java.lang.String.startsWith(java.lang.String)' on a null object reference
E/ImageLoader(27386): java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.startsWith(java.lang.String)' on a null object reference
E/ImageLoader(27386):   at com.android.okhttp.internal.http.StatusLine.<init>(StatusLine.java:24)
E/ImageLoader(27386):   at com.android.okhttp.Response$Builder.statusLine(Response.java:419)
E/ImageLoader(27386):   at com.android.okhttp.internal.http.JavaApiConverter.createOkResponse(JavaApiConverter.java:116)
E/ImageLoader(27386):   at com.android.okhttp.internal.http.ResponseCacheAdapter.get(ResponseCacheAdapter.java:53)
E/ImageLoader(27386):   at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:269)
E/ImageLoader(27386):   at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:373)
E/ImageLoader(27386):   at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:323)
E/ImageLoader(27386):   at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:491)
E/ImageLoader(27386):   at com.android.okhttp.internal.http.DelegatingHttpsURLConnection.getResponseCode(DelegatingHttpsURLConnection.java:105)
E/ImageLoader(27386):   at com.android.okhttp.internal.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:25)
E/ImageLoader(27386):   at com.nostra13.universalimageloader.core.download.BaseImageDownloader.getStreamFromNetwork(BaseImageDownloader.java:113)
E/ImageLoader(27386):   at com.nostra13.universalimageloader.core.download.BaseImageDownloader.getStream(BaseImageDownloader.java:84)
E/ImageLoader(27386):   at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.downloadImage(LoadAndDisplayImageTask.java:290)
E/ImageLoader(27386):   at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.tryCacheImageOnDisk(LoadAndDisplayImageTask.java:273)
E/ImageLoader(27386):   at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.tryLoadBitmap(LoadAndDisplayImageTask.java:229)
E/ImageLoader(27386):   at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.run(LoadAndDisplayImageTask.java:135)
E/ImageLoader(27386):   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
E/ImageLoader(27386):   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
E/ImageLoader(27386):   at java.lang.Thread.run(Thread.java:818)

这似乎是 okhttp 中的错误,而不是 Universal-Image-Loader 中的错误。代码做了这样的事情,它在调用 getResponseCode 时崩溃:

String encodedUrl = Uri.encode(url, ALLOWED_URI_CHARS);
HttpURLConnection conn = (HttpURLConnection) new URL(encodedUrl).openConnection();
conn.getResponseCode()

我设法通过在调用 getResponseCode 之前禁用连接上的缓存来解决这个问题:

conn.setUseCaches(false);

有谁知道为什么会发生这种情况以及在哪些确切条件下发生?这可能与服务器设置有关,也许与缓存有关?

【问题讨论】:

标签: android android-5.0-lollipop okhttp universal-image-loader


【解决方案1】:

造成这种情况的原因是 ResponseCache 的自定义实现。在实现 CacheResponse.getHeaders() 时,需要将状态行放在 multimap 的 null 键中。见:http://developer.android.com/reference/java/net/CacheResponse.html#getHeaders()

如果不这样做,会导致 okhttp 失败并返回 NullPointerException,这是 okhttp 中的一个错误。

我正在复制来自https://code.google.com/p/android/issues/detail?id=160522#c5 的 okhttp 问题跟踪器的完整说明,因为谷歌代码即将关闭...


状态行周围的 HttpURLConnection API 有一些奇怪之处。当我实现 ResponseCacheAdapter / JavaApiConverter 时,我假设某些行为是这样做的,而在 JavaDocs 中有时没有明确指定该行为。

根本原因是 Android 假定状态行(例如,指示响应代码的响应部分,一条消息)作为带有 null 键的标头保存。当您查看索引为零的标头时,API 文档中提到了这一点,但在返回 Map 或采用 String 的方法中并不明确。

请看这里:http://developer.android.com/reference/java/net/URLConnection.html#getHeaderFields()
还有:http://developer.android.com/reference/java/net/CacheResponse.html#getHeaders()

OkHttp 的 HttpURLConnection 实现就是这样做的,Android 上的许多版本都是这种情况。

这段代码: https://github.com/appcelerator/titanium_mobile/blob/master/android/titanium/src/java/org/appcelerator/titanium/util/TiResponseCache.java#L416

建议缓存实现无法正确处理具有空键的响应标头。带有空键的标头被写为带有字符串“null”的键的标头,因此它不是往返的。当缓存的标头被反序列化时,我们最终没有带有空键的标头,这意味着 OkHttp 代码无法从 CacheResponse 重建状态行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-22
    • 1970-01-01
    • 1970-01-01
    • 2015-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-15
    相关资源
    最近更新 更多