在你将鼠标悬停在关闭按钮上之前。请仔细阅读这个问题。
序言
显然,此异常是由在主线程上运行网络操作引起的。但是,从stacktrace可以看到,这个错误源于doInBackgroundAsyncTask!在这一点之后,我也不会转换到主线程上。
有趣的是,我不能在我的设备上复制这个问题。对于我的绝大多数用户来说,这也不是一个问题。因此,它不能是一般的实现错误。
步骤
主线
某些原因导致频道列表刷新(手动或初始加载)
我的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方法。必须帮助

10-06 12:09
查看更多