无法在 Android 4.4 KitKat 上快速关闭 ChunkedInputStream

Posted

技术标签:

【中文标题】无法在 Android 4.4 KitKat 上快速关闭 ChunkedInputStream【英文标题】:Unable to close ChunkedInputStream quickly on Android 4.4 KitKat 【发布时间】:2013-12-16 20:59:08 【问题描述】:

我有一个 android Daydream,它使用 Twitter4j 的流实现来显示推文流。这在 Android 4.2 和 4.3 上运行良好。但是,在 4.4 上,我无法快速关闭流(onDreamingStopped)。

我收到了this stacktrace,但NetworkOnMainThreadException 不是问题。

这个问题似乎与this issue 有关,围绕连接重用。 This OkHttp changeset(合并到 Android here)改变了 closeChunkedInputStream 上的行为方式。它不再简单地将自己标记为“已关闭”,然后如果还有更多数据要读取则断开套接字,它现在尝试首先丢弃流以启用套接字的快速重用。如果它未能丢弃流,它会像以前一样断开套接字。

我现在得到NetworkOnMainThreadException 的原因是(正如您从堆栈跟踪中看到的)丢弃流现在尝试从流中读取。这很容易解决 - 我只是在关闭 Daydream 时将其放入 AsyncTask 并忘记它。

问题是流没有在超时设置内被丢弃。查看HttpTransport#discardStream method of the latest version of the source,它在套接字上指定了100ms 的超时时间(原始提交指定为30ms),然后尝试从流(Util.skipAll)中读取以清空缓冲区。但是,我看到BufferedInputStream.read() 调用出现了多秒的延迟。这种延迟的长度似乎有所不同。

这不是一个大问题 - 因为我现在必须从 UI 线程关闭这个流,我不会导致 onDreamingStopped 调用需要很长时间才能返回(这导致白日梦停留按返回/主页后在屏幕上很长时间 - 我最初的错误报告导致我跟随这个兔子洞)。但是,它确实会在它应该关闭后让这个连接挂起一段时间。

我已经测试了使用两个不同活动级别的 Twitter 帐户关闭信息流需要多长时间。第一个在我试图关闭流的时候没有看到任何活动,而且我一直看到调用大约需要 30 秒。第二个账户有更多的活动,关闭流的时间在这个账户上变化很大——从 1.5 到 30 秒不等。当有新推文进入时(新块写入流),它似乎会立即关闭。

为什么我看到在 KitKat 上关闭流时出现这种延迟?为什么它不遵守正在设置的 100 毫秒超时?

这类似于Android KitKat HttpURLConnection disconnect AsyncTask - 虽然这可能在底层使用FixedLengthInputStream,但相同的更改已应用于该类的close 方法。

【问题讨论】:

【参考方案1】:

这是 OkHttp 中的一个错误。修复是here。如果您不介意在应用程序中包含 OkHttp jar,则可以在 AOSP 更新以包含修复程序之前解决此问题。

OkHttpClient okHttpClient = new OkHttpClient();
URL.setURLStreamHandlerFactory(okHttpClient);

OkHttp 1.3 的修复没有及时合并;您需要等待以后的版本或自己构建jar

【讨论】:

谢谢杰西,感激不尽。今晚将构建并包含这个,在 KitKat 中对我来说非常有问题! 不幸的是,这对我不起作用;我看到与以前相同的行为。我已经尝试从您的修复分支以及 master 的最新更改构建。 JDK 1.7.0_45,Android 4.4.2 目标。 My changes. 我也检查了 Twitter4J,看看它是否设置了自己的流处理程序;那里空无一物。它挂在BufferedInputStream.read 电话/ 好的,杰西,我已经取得了一些进展。我现在遇到了一个不同的问题,自 1 月 18 日以来的所有 OkHttp 版本。我有 gone into detail here。 Righto 在源代码中修复了这个问题,我仍然看到我上面的内容;它挂在BufferedInputStream.read 电话上。在调试器尝试关闭时点击暂停和this is the stack。

以上是关于无法在 Android 4.4 KitKat 上快速关闭 ChunkedInputStream的主要内容,如果未能解决你的问题,请参考以下文章

android 4.4(KitKat)上,如何开发SMS功能的APP

透明状态栏 - Android 4.4 (KitKat) 之前

在 android 4.4+ 或 kitkat 中隐藏状态栏

Android - 可扩展列表视图 SetIndicatorBounds 在 Kitkat android-4.4 中不起作用

隐藏滚动条 Android KitKat 4.4

Android 4.4系统 KitKat到底都有哪些能耐