Closed thorbenprimke closed 8 years ago
See https://github.com/square/okhttp/issues/869 for more context.
@sjudd So what would be the best temp fix in this case in your opinion?
It's pretty clear from the icebox designation that their not planning on fixing the bug in OkHttp.
I'm inclined to take @swankjesse at his word and assume that this call is non-blocking and won't have any negative impact on the performance of the library, in which case we can also just ignore this warning.
If you think this call is impacting your application, I'd be curious to see timings indicating how long we're spending in cancel()
(traceview might help here). We could consider posting cancellations to a background thread in OkHttpStreamFetcher
, but doing so may introduce other performance problems.
By ignoring you mean changing ThreadPolicy or try-catch block or maybe something else?
@RobertoArtiles We don't set a strict mode thread policy, if you do so in your app you may want to consider changing it so that it does not throw for this kind of exception. Try/catch sounds ugly and would probably be hard to write effectively.
Do also feel free to try posting cancel()
to a background thread in OkHttpStreamFetcher
to avoid the problem. If you don't notice a performance impact and you are concerned about the strict mode error then forking the OkHttp integration library is not an unreasonable course of action.
I don't set ThreadPolicy myself. NetworkOnMainThreadException is the exception which system throws (if app targets API 11+) when you do networking operations on the the main thread. The question is not about the performance, but about this exception which leads to the app crash and which you guaranteed to get during a ListView fast scroll (I don't call cancel()
my self). And I'm trying to think of the best solution in this case.
android.os.NetworkOnMainThreadException
at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1145)
at com.android.org.conscrypt.OpenSSLSocketImpl.close(OpenSSLSocketImpl.java:1009)
at com.squareup.okhttp.Connection.void closeIfOwnedBy(java.lang.Object)(:136)
at com.squareup.okhttp.OkHttpClient$1.void closeIfOwnedBy(com.squareup.okhttp.Connection,java.lang.Object)(:70)
at com.squareup.okhttp.internal.http.HttpConnection.void closeIfOwnedBy(java.lang.Object)(:134)
at com.squareup.okhttp.internal.http.HttpTransport.void disconnect(com.squareup.okhttp.internal.http.HttpEngine)(:132)
at com.squareup.okhttp.internal.http.HttpEngine.void disconnect()(:465)
at com.squareup.okhttp.Call.void cancel()(:124)
at com.squareup.okhttp.Dispatcher.void cancel(java.lang.Object)(:134)
at com.squareup.okhttp.OkHttpClient.com.squareup.okhttp.OkHttpClient cancel(java.lang.Object)(:506)
at com.bumptech.glide.integration.okhttp.OkHttpStreamFetcher.void cancel()(:59)
at com.bumptech.glide.load.model.ImageVideoModelLoader$ImageVideoFetcher.void cancel()(:120)
at com.bumptech.glide.load.engine.DecodeJob.void cancel()(:132)
at com.bumptech.glide.load.engine.EngineRunnable.void cancel()(:46)
at com.bumptech.glide.load.engine.EngineJob.void cancel()(:119)
at com.bumptech.glide.load.engine.EngineJob.void removeCallback(com.bumptech.glide.request.ResourceCallback)(:93)
at com.bumptech.glide.load.engine.Engine$LoadStatus.void cancel()(:52)
at com.bumptech.glide.request.GenericRequest.void cancel()(:283)
at com.bumptech.glide.request.GenericRequest.void clear()(:301)
at com.bumptech.glide.GenericRequestBuilder.com.bumptech.glide.request.target.Target into(com.bumptech.glide.request.target.Target)(:606)
at com.bumptech.glide.GenericRequestBuilder.com.bumptech.glide.request.target.Target into(android.widget.ImageView)(:651)
at com.bumptech.glide.DrawableRequestBuilder.com.bumptech.glide.request.target.Target into(android.widget.ImageView)(:436)
at com.package_name.FriendView.void setBaseUserData(com.package_name.model.User)(:38)
at com.package_name.FriendsOverlayView$FriendsAdapter.void bindView(android.view.View,android.content.Context,android.database.Cursor)(:456)
at android.widget.CursorAdapter.getView(CursorAdapter.java:254)
at com.commonsware.cwac.merge.MergeAdapter.android.view.View getView(int,android.view.View,android.view.ViewGroup)(:272)
at android.widget.HeaderViewListAdapter.getView(HeaderViewListAdapter.java:220)
at android.widget.AbsListView.obtainView(AbsListView.java:2255)
at android.widget.ListView.makeAndAddView(ListView.java:1790)
at android.widget.ListView.fillDown(ListView.java:691)
at android.widget.ListView.fillGap(ListView.java:655)
at android.widget.AbsListView.trackMotionScroll(AbsListView.java:5143)
at android.widget.AbsListView$FlingRunnable.run(AbsListView.java:4254)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)
at android.view.Choreographer.doCallbacks(Choreographer.java:574)
at android.view.Choreographer.doFrame(Choreographer.java:543)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5086)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit
Ah right, in that case it's set by default in dev builds. You can override it yourself manually.
Again the "best" solution here would be to post cancel to a background thread to work around the okhttp issue. Doing so should be relatively straightforward if you're interested. I'd be happy to see a pull request.
Actually I just looked back at our implementation for HttpUrlConnections, and we don't call cancel to avoid this exception: https://github.com/bumptech/glide/blob/master/library/src/main/java/com/bumptech/glide/load/data/HttpUrlFetcher.java#L107.
I'd been assuming this was limited to OkHttp, but since it's not it's probably worth considering more broadly.
For now it seems like we can probably just not call cancel at all.
Ok, thanks :)
@sjudd I think posting the cancel for a background thread is the best solution, but it should be the application's job to do that. Not OkHttp's.
That's why he opened the other bug, to solve it in the library (when calling DataFetcher.cancel
) regardless of what I/O integration method you use.
FYI, OkHttp now cancels without the warning.
Both okhttp3 integration libs (v3 and v4) can call cancel safely now, according to @swankjesse. Reopened so the commented out code can be reverted at least for those new versions.
@swankjesse do you know since when it is safe to call it and if we can detect if the version on the classpath is newer than that (preferably in a proguard-safe way)? This would be useful for the okhttp2 integration libs.
It's best in OkHttp 2.7 and 3.0.
@swankjesse Is there a way to detect [2.7, 3.0)
?
Not specifically. Let’s just do canceling for 3.x and above.
Fixed in master here: https://github.com/bumptech/glide/commit/91c75ee589d0c57aa114734a3d5ff7d0571be6fe
After upgrading to 3.4, it intermittently hits a NetworkOnMainThreadException. I haven't had time to investigate it deeper except for removing the OkHttp registration line.
Init code:
Glide.get(this).register(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory());
Calling code:
Exception trace: