Joe Richard Joe Richard -4 years ago 249
Java Question

Retrofit - android.os.NetworkOnMainThreadException

I am using Retrofit 2 to get json and parse it to POJO. My purpose is getting one value of that object.

compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'


My REST client:

public interface MyClient {

@GET("/part1/part2")
Call<MyItem> getMyItem(@Query("param1") String param1,
@Query("param2") String param2,
@Query("param3") String param3);

}


Here I found great great tool to create service:

public class ServiceGenerator {

public static final String API_BASE_URL = "http://my.api.com";

private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();

private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create());

public static <S> S createService(Class<S> serviceClass) {
Retrofit retrofit = builder.client(httpClient.build()).build();
return retrofit.create(serviceClass);
}
}


Then I am creating new service using Service generator class:

MyClient api = ServiceGenerator.createService(MyClient.class);
Call<MyItem> call = api.getMyItem(param1, param2, param3);
MyItem myItem= null;
try {
myItem= call.execute().body();
Log.d("MyTag", myItem.getValue());
} catch (IOException e) {
e.printStackTrace();
}


When I am trying to run this code I am getting this error:


android.os.NetworkOnMainThreadException
at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1147)
at java.net.InetAddress.lookupHostByName(InetAddress.java:418)
at java.net.InetAddress.getAllByNameImpl(InetAddress.java:252)
at java.net.InetAddress.getAllByName(InetAddress.java:215)
at okhttp3.Dns$1.lookup(Dns.java:39)
at okhttp3.internal.http.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:173)
at okhttp3.internal.http.RouteSelector.nextProxy(RouteSelector.java:139)
at okhttp3.internal.http.RouteSelector.next(RouteSelector.java:81)
at okhttp3.internal.http.StreamAllocation.findConnection(StreamAllocation.java:174)
at okhttp3.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:127)
at okhttp3.internal.http.StreamAllocation.newStream(StreamAllocation.java:97)
at okhttp3.internal.http.HttpEngine.connect(HttpEngine.java:289)
at okhttp3.internal.http.HttpEngine.sendRequest(HttpEngine.java:241)
at okhttp3.RealCall.getResponse(RealCall.java:240)
at okhttp3.RealCall$ApplicationInterceptorChain.proceed(RealCall.java:198)
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:160)
at okhttp3.RealCall.execute(RealCall.java:57)
at retrofit2.OkHttpCall.execute(OkHttpCall.java:177)
at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall.execute(ExecutorCallAdapterFactory.java:87)
at uz.cp.ox.data.MyRepository.getMyItem(MyRepository.java:31)
at uz.cp.ox.presenters.MyPresenter.do(MyPresenter.java:30)
at uz.cp.ox.activities.MyActivity.onClick(MyActivity.java:52)
at android.view.View.performClick(View.java:4756)
at android.view.View$PerformClick.run(View.java:19749)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)


I thought that Retrofit automatically does the job in the background thread. Or I misunderstood something. What is wrong in this situation and how to solve it?

Answer Source

I thought that Retrofit automatically does the job in the background thread.

It does if you use the asynchronous version - enqueue. You're using the synchronous version, which runs on the calling thread.

Call it this way instead:

MyClient api = ServiceGenerator.createService(MyClient.class);
Call<MyItem> call = api.getMyItem(param1, param2, param3);
call.enqueue(new Callback<MyItem>() {
    @Override
    public void onResponse(Call<MyItem> call, Response<MyItem> response) {
        MyItem myItem=response.body();
    }

    @Override
    public void onFailure(Call<MyItem> call, Throwable t) {
        //Handle failure
    }
});

In onResponse(), use response.body() to get your response, such as:
MyItem myItem=response.body();

Edit: Fixed onResponse() & onFailure() signatures and added example to onRespnose().

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download