在你将鼠标悬停在关闭按钮上之前。请仔细阅读这个问题。
序言
显然,此异常是由在主线程上运行网络操作引起的。但是,从stacktrace可以看到,这个错误源于doInBackground
的AsyncTask
!在这一点之后,我也不会转换到主线程上。
有趣的是,我不能在我的设备上复制这个问题。对于我的绝大多数用户来说,这也不是一个问题。因此,它不能是一般的实现错误。
步骤
主线
某些原因导致频道列表刷新(手动或初始加载)
我的api库被调用(附录1)
背景线AsyncTask
调用api库以获取url的主体(附录2)
我的缓存库检查主体是否已保存,它不会更改Thread
。
api库调用必要的OkHttp
方法来拉取url的主体(附录3)
堆栈跟踪
Fatal Exception: java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:309)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Caused by android.os.NetworkOnMainThreadException
at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1273)
at libcore.io.BlockGuardOs.recvfrom(BlockGuardOs.java:249)
at libcore.io.IoBridge.recvfrom(IoBridge.java:549)
at java.net.PlainSocketImpl.read(PlainSocketImpl.java:481)
at java.net.PlainSocketImpl.access$000(PlainSocketImpl.java:37)
at java.net.PlainSocketImpl$PlainSocketInputStream.read(PlainSocketImpl.java:237)
at okio.Okio$2.read(SourceFile:139)
at okio.AsyncTimeout$2.read(SourceFile:211)
at okio.RealBufferedSource.indexOf(SourceFile:306)
at okio.RealBufferedSource.indexOf(SourceFile:300)
at okio.RealBufferedSource.readUtf8LineStrict(SourceFile:196)
at okhttp3.internal.http.Http1xStream.readResponse(SourceFile:184)
at okhttp3.internal.http.Http1xStream.readResponseHeaders(SourceFile:125)
at okhttp3.internal.http.HttpEngine.readNetworkResponse(SourceFile:723)
at okhttp3.internal.http.HttpEngine.access$200(SourceFile:81)
at okhttp3.internal.http.HttpEngine$NetworkInterceptorChain.proceed(SourceFile:708)
at okhttp3.internal.http.HttpEngine.readResponse(SourceFile:563)
at okhttp3.RealCall.getResponse(SourceFile:241)
at okhttp3.RealCall$ApplicationInterceptorChain.proceed(SourceFile:198)
at okhttp3.RealCall.getResponseWithInterceptorChain(SourceFile:160)
at okhttp3.RealCall.execute(SourceFile:57)
at com.mypackagename.app.http.Api.getBody(SourceFile:1472)
at com.mypackagename.app.tasks.GetChannelListTask$2.renewCache(SourceFile:72)
at com.mypackagename.app.utils.Cache.get(SourceFile:27)
at com.mypackagename.app.tasks.GetChannelListTask.doInBackground(SourceFile:69)
at com.mypackagename.app.tasks.GetChannelListTask.doInBackground(SourceFile:24)
at android.os.AsyncTask$2.call(AsyncTask.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
附录1
public void getChannelList(final IGetChannelListCallback callback) {
try {
GetChannelListTask task = new GetChannelListTask(mContext.get(), callback);
AsyncTaskCompat.executeParallel(task);
} catch (RejectedExecutionException e) {
Crashlytics.logException(e);
}
}
附录2
protected ArrayList<Channel> doInBackground(String... urls) {
final ArrayList<Channel> channelList = new ArrayList<Channel>();
// ...
String json = Cache.get(context, GET_CHANNELS_CACHE, GET_CHANNELS_CACHE_TIME, new IBadCache() {
public String renewCache() {
return Api.getInstance(context).getBody(GET_CHANNELS_URL);
}
});
// ...
return channelList;
}
附录3
@WorkerThread
@NonNull
public String getBody(@NonNull final String url) {
try {
Request request = new Request.Builder()
.url(logUrl(url))
.build();
Response response = mClient.newCall(request).execute();
return response.body().string();
} catch (IOException e) {
Utils.log("API", "E::"+e.toString());
} catch (SecurityException e) {
reportNoInternetPermission();
}
return "";
}
更新1
检查线程导致预期的:
refreshChannelList: MainThread: true
getChannelList: MainThread: true
onPreExecute: MainThread: true
doInBackground: MainThread: false
renewCache: MainThread: false
getBody: MainThread: false
onPostExecute: MainThread: true
在
doInBackground
时移动到后台线程并继续执行OkHttp
调用,在onPostExecute
时返回一次主线程。 最佳答案
嗯,在doinbackground方法中,当你做某事(使用上下文调用某个操作)时,看起来像是你的问题。如果活动/片段等的上下文实例(取自ui组件)意味着使用上下文的操作使用mainthread执行。这就是为什么你会有这样的例外。
试着执行这个
String json = Cache.get(context, GET_CHANNELS_CACHE, GET_CHANNELS_CACHE_TIME, new IBadCache() {
public String renewCache() {
return Api.getInstance(context).getBody(GET_CHANNELS_URL);
}
});
在
@Override
protected void onProgressUpdate(Object... values) {
super.onProgressUpdate(values);
}
与publishprogress(object obj)一起;关于doinbackground方法。必须帮助