Unable to close ChunkedInputStream quickly on Android 4.4 KitKat

冷暖自知 提交于 2019-12-22 09:41:58

问题


I've got an Android Daydream that displays a stream of tweets using Twitter4j's streaming implementation. This works fine on Android 4.2 and 4.3. On 4.4 however, I cannot quickly close the stream (in onDreamingStopped).

I'm getting this stacktrace but the NetworkOnMainThreadException isn't the problem.

The problem appears to be related to this issue, around connection reuse. This OkHttp changeset (which gets merged into Android here) changes the way that close behaves on ChunkedInputStream. Instead of simply marking itself as "closed" and then disconnecting the socket if there was still more data to be read, it now attempts to discard the stream first to enable quick reuse of the socket. If it fails to discard the stream, it then disconnects the socket as before.

The reason I'm now getting a NetworkOnMainThreadException is because (as you see from the stack trace) discarding the stream now attempts to read from the stream. That's easy enough to fix - I just drop it in an AsyncTask when closing my Daydream and forget about it.

The problem is that the stream isn't being discarded within the timeout set. Looking at the HttpTransport#discardStream method of the latest version of the source, it specifies a 100ms timeout on the socket (the original commit specified 30ms), then tries to read from the stream (Util.skipAll) to empty the buffer. However I'm seeing a multiple-second delay around the BufferedInputStream.read() call. The length of this delay seems to vary.

This isn't a huge problem - since I now have to close this stream off the UI thread anyway, I'm not causing the onDreamingStopped call to take a long time to return (which was causing the daydream to stay on the screen for a long time after pressing back/home - my initial bug report which caused me to follow this rabbit hole). However, it does leave this connection hanging around for a while after it's supposed to be closed.

I've tested how long it takes to close the stream with two Twitter accounts of varying activity levels. The first one didn't see any activity in the time I was trying to close the stream, and I was consistently seeing the call take around 30 seconds. The second account has much more activity on it, and the time to close the stream was much more varied on this one - anywhere from 1.5 to 30 seconds. It appears to close instantly when a new tweet comes in (a new chunk is written to the stream).

Why am I seeing this delay in closing a stream on KitKat? Why does it not respect the 100ms timeout that's being set?

This is similar to Android KitKat HttpURLConnection disconnect AsyncTask - although that's presumably using a FixedLengthInputStream under the hood, the same change has been applied to the close method of that class.


回答1:


This was a bug in OkHttp. Fix is here. If you don't mind including the OkHttp jar in your application, you can work-around this problem until AOSP is updated to include the fix.

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

The fix was not merged in time for OkHttp 1.3; you'll need to wait for a later release or build the jar yourself.



来源:https://stackoverflow.com/questions/20306498/unable-to-close-chunkedinputstream-quickly-on-android-4-4-kitkat

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!