Retrofit 2错误:NetworkOnMainThreadException

问题描述:

我试图在Android中对我的服务器执行同步请求。 (代码完美地在一个普通的Java项目中工作)Retrofit 2错误:NetworkOnMainThreadException

我知道同步请求不应该在主线程上完成,所以我开始一个新的线程在网络完成。我也知道可以进行异步调用,但同步调用更适合我的用例。

bool networkingIsDoneHere(){ 
    dostuff(); 
    int number = doNetworkCall(); 
    if(number < 500){ 
    return true; 
    } 
    return false 
} 

问题是我仍然收到“NetworkOnMainThreadException”错误。在侧线上执行时,改装是否以某种方式在主线上运行?

开始新的线程:

Thread timerThread = new Thread() { 
     @Override 
     public void run() { 
      while (true) { 
       try { 
        networkingIsDoneHere(); 
        sleep(getExecutionInterval()); 
       } catch (Exception e) { 
        e.printStackTrace(); 
       } 
      } 
     } 
    }; 

    @Override 
    public void startRule() { 
     timerThread.start(); 
    } 

改造代码

private Retrofit createRetrofitAdapter() throws Exception { 
     return retrofit = new Retrofit.Builder() 
       .baseUrl("https://maps.googleapis.com/maps/api/") 
       .addConverterFactory(GsonConverterFactory.create()) 
       .build(); 

    } 

    public interface ApiGoogleMapsService { 
     @GET("url...") 
     Call<MapApiCall> getDurationJson(@Query("origins") String origin, @Query("destinations") String destination); 
    } 

错误:

 Caused by: android.os.NetworkOnMainThreadException 
be.kul.gj.annotationfw W/System.err:  at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1273) 
be.kul.gj.annotationfw W/System.err:  at com.android.org.conscrypt.OpenSSLSocketImpl.shutdownAndFreeSslNative(OpenSSLSocketImpl.java:1131) 
be.kul.gj.annotationfw W/System.err:  at com.android.org.conscrypt.OpenSSLSocketImpl.close(OpenSSLSocketImpl.java:1126) 
be.kul.gj.annotationfw W/System.err:  at okhttp3.internal.Util.closeQuietly(Util.java:105) 
be.kul.gj.annotationfw W/System.err:  at okhttp3.internal.http.StreamAllocation.deallocate(StreamAllocation.java:260) 
be.kul.gj.annotationfw W/System.err:  at okhttp3.internal.http.StreamAllocation.connectionFailed(StreamAllocation.java:289) 
be.kul.gj.annotationfw W/System.err:  at okhttp3.internal.http.HttpEngine.close(HttpEngine.java:429) 
be.kul.gj.annotationfw W/System.err:  at okhttp3.RealCall.getResponse(RealCall.java:270) 
be.kul.gj.annotationfw W/System.err:  at okhttp3.RealCall$ApplicationInterceptorChain.proceed(RealCall.java:198) 
be.kul.gj.annotationfw W/System.err:  at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:160) 
be.kul.gj.annotationfw W/System.err:  at okhttp3.RealCall.execute(RealCall.java:57) 
be.kul.gj.annotationfw W/System.err:  at retrofit2.OkHttpCall.execute(OkHttpCall.java:177) 
be.kul.gj.annotationfw W/System.err:  at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall.execute(ExecutorCallAdapterFactory.java:87) 
be.kul.gj.annotationfw W/System.err:  at model.GoogleMapsAccess.getTravelDuration(GoogleMapsAccess.java:52) 
be.kul.gj.annotationfw W/System.err:  at rule.RoutePickupRule.condition(RoutePickupRule.java:40) 

不是启动一个单独的线程一个新的线程自己,改造可以自动完成的请求。您可以拨打enqueue();来完成此操作。

Call<MapApiCall> call = api.getDurationJson(foo); 

call.enqueue(new Callback<MapApiCall>() { 
     @Override 
     public void onResponse(Call<MapApiCall> call, Response<MapApiCall> response) { 
      //Do something with response 
     } 

     @Override 
     public void onFailure(Call<MapApiCall> call, Throwable t) { 
      //Do something with failure 
     } 
    }); 

如果你想同步请求使用​​你单独的线程中:

Call<MapApiCall> call = api.getDurationJson(); 
MapApiCall apiCall = call.execute().body(); 

如果由于某种原因,要禁用NetworkOnMainThreadException不使用线程使用:

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); 
StrictMode.setThreadPolicy(policy); 

但是,如果您不知道StrictMode是什么,那么不建议使用它,请不要使用它。

+1

我在示例中添加了“networkingIsDoneHere”。它显示了我为什么不想使用此解决方案。我需要在我的“if case”中调用网络调用的结果,并返回false。 –

+0

对不起,我一定误会了。你在线程中使用execute()吗?我已经更新了我的答案。 –

+0

认为我发现了我的问题。我使用带有Runnable的Handler从主线程中的其他位置调用代码,但这似乎并不在单独的线程上运行。我会接受你的anwser,因为它是一般概念的一个很好的解释:) –

你的问题是createRetrofitAdapter方法在主线程上被调用。这就是您创建新Retrofit实例的地方,但绝对无法在UI线程上完成。最简单的捷径是在AsyncTask中完成。