这个NetworkOnMainThreadException的原因是什么

时间:2016-06-08 12:32:24

标签: android android-asynctask okhttp3

将鼠标悬停在关闭按钮上之前。请完整阅读这个问题。

前言

显然,此异常是由在主线程上运行网络操作引起的。但是,正如您从堆栈跟踪中看到的,此错误源自doInBackground的{​​{1}}!在那之后我也没有转换到主线程。

有趣的是,我无法在我的设备上复制此问题。对于绝大多数用户而言,这也不是一个问题。因此,它不能是一般的实现错误。

步骤

  1. 主线
  2. 某些东西导致频道列表刷新(无论是手动还是初始加载)
  3. 我的API库被调用(附录1)
  4. 背景线程
  5. AsyncTask调用API库以获取URL的主体(附录2)
  6. 我的缓存库会检查正文是否已保存,但不会更改AsyncTask
  7. API库调用必要的Thread方法来提取URL的主体(附录3)
  8. 堆栈跟踪

    OkHttp

    附录1

    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)
    

    附录2

    public void getChannelList(final IGetChannelListCallback callback) {
        try {
            GetChannelListTask task = new GetChannelListTask(mContext.get(), callback);
            AsyncTaskCompat.executeParallel(task);
        } catch (RejectedExecutionException e) {
            Crashlytics.logException(e);
        }
    }
    

    附录3

    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;
    }
    

    更新1

    检查线程导致了预期的结果:

    @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 "";
    }
    

    移至refreshChannelList: MainThread: true getChannelList: MainThread: true onPreExecute: MainThread: true doInBackground: MainThread: false renewCache: MainThread: false getBody: MainThread: false onPostExecute: MainThread: true 后台线程并继续doInBackground来电,在OkHttp返回主线程。

1 个答案:

答案 0 :(得分:0)

嗯,看起来像你在doInbackground方法中做某事(用上下文用法调用一些操作)的问题。如果Activity / Fragment等的上下文实例(取自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);
    }
}); 

on

@Override
protected void onProgressUpdate(Object... values) {
  super.onProgressUpdate(values);

}

使用publishProgress(Object obj);在doInbackground方法上。它必须帮助