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

4
我有一个使用Twitter4j的流实现显示推文流的Android Daydream。在Android 4.2和4.3上运行良好。但是在4.4上,我无法快速关闭流(在onDreamingStopped)。
我得到了这个堆栈跟踪,但NetworkOnMainThreadException不是问题所在。
问题似乎与此问题有关,涉及连接重用。 这个OkHttp更改集(在此处合并到Android更改了closeChunkedInputStream上的行为。现在,它不仅将自己标记为“关闭”,然后在仍有更多数据需要读取时断开套接字,而且还尝试首先丢弃流以便快速重用套接字。如果无法丢弃流,则像以前一样断开套接字。
我现在得到NetworkOnMainThreadException的原因是因为(从堆栈跟踪中可以看出)丢弃流现在尝试从流中读取。这很容易解决-当关闭我的Daydream并忘记它时,我只需将其放入AsyncTask中即可。
问题是流未在设置的超时时间内被丢弃。查看源代码最新版本的HttpTransport#discardStream方法,它对套接字指定了100ms的超时时间(原始提交指定了30ms),然后尝试从流中读取(Util.skipAll)以清空缓冲区。但我看到大约在BufferedInputStream.read()中存在多秒延迟。此延迟的长度似乎有所不同。
这不是一个很大的问题 - 因为我现在必须在UI线程上关闭这个流,所以我不会导致onDreamingStopped调用需要很长时间才能返回(这导致了Daydream在按下back/home后仍停留在屏幕上很长时间 - 这是我最初报告的错误,导致我跟着这个兔子洞)。但是,在它应该被关闭之后,它确实会让这个连接挂起一段时间。
我已经测试了两个Twitter账户的流关闭时间,这两个账户的活动水平有所不同。第一个账户在我尝试关闭流的时间内没有看到任何活动,我一直看到调用需要约30秒。第二个账户上的活动要多得多,关闭流的时间在这个账户上变化很大 - 从1.5秒到30秒不等。当新推文进来时(一个新块被写入流中),它似乎会立即关闭。 为什么在KitKat上关闭流时会出现延迟?为什么它不遵守设置的100ms超时? 这类似于Android KitKat HttpURLConnection disconnect AsyncTask - 虽然那里可能使用了底层的FixedLengthInputStream,但是相同的更改已经应用于该类的close方法。
1个回答

5
这是一个OkHttp的bug。修复方法在这里。如果您不介意在应用程序中包含OkHttp jar文件,您可以绕过此问题,直到AOSP更新以包含修复程序。
OkHttpClient okHttpClient = new OkHttpClient();
URL.setURLStreamHandlerFactory(okHttpClient);

修复程序在OkHttp 1.3中尚未合并;您需要等待以后的版本发布或自己构建jar

很遗憾,这对我并没有起作用;我看到的还是之前的相同行为。我已经尝试了从您的修复分支构建,以及最新的master更改。JDK 1.7.0_45,Android 4.4.2目标。 【我的更改】(https://gist.github.com/adamsp/2c32ddd9d3cec1985c6a)。 - Adam S
我也检查了Twitter4J,看看它是否设置了自己的流处理程序;但没有发现。它卡在BufferedInputStream.read调用上。 - Adam S
1
好的Jesse,我有了一些进展。现在我遇到了一个不同的问题,自1月18日以来,在所有OkHttp构建中都存在这个问题。我已经在这里详细说明了 - Adam S
1
好的,我已经在源代码中修复了它,但我仍然看到与之前相同的问题;它卡在 BufferedInputStream.read 调用上。在调试器中按下暂停按钮时,它正在尝试关闭,这是堆栈跟踪 - Adam S
嗯。那个堆栈提示存在分块编码问题。奇怪。有URL吗? - Jesse Wilson
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接