web-dev-qa-db-fra.com

Retrofit - Android.os.NetworkOnMainThreadException

J'utilise Retrofit 2 pour obtenir json et l'analyser en POJO. Mon but est d'obtenir une valeur de cet objet.

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

Mon REST:

public interface MyClient {

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

}

Ici J'ai trouvé un excellent outil pour créer un 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);
    }
}

Ensuite, je crée un nouveau service en utilisant la classe Générateur de services:

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

Lorsque j'essaie d'exécuter ce code, j'obtiens cette erreur:

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

Je pensais que Retrofit fait automatiquement le travail dans le thread d'arrière-plan. Ou j'ai mal compris quelque chose. Qu'est-ce qui ne va pas dans cette situation et comment y remédier?

18
Joe Richard

Je pensais que Retrofit fait automatiquement le travail dans le thread d'arrière-plan.

C'est le cas si vous utilisez la version asynchrone - enqueue. Vous utilisez la version synchrone, qui s'exécute sur le thread appelant.

Appelez-le de cette façon à la place:

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

Dans onResponse (), utilisez response.body() pour obtenir votre réponse, par exemple:
MyItem myItem=response.body();

Edit: correction des signatures onResponse () onFailure () et ajout d'un exemple à onRespnose ().

38
NightSkyDev

Vous appelez webservice sur le thread principal, c'est pourquoi vous avez cette erreur ' Android.os.NetworkOnMainThreadException '.

Vous pouvez utiliser le codage ci-dessus répondu par NightSkyDev pour obtenir les données que vous voulez.

3
Sai Soe Harn

Dans Retrofit, deux types d'exécution de méthode ont lieu - Enqueue - Fonctionne sur le thread d'arrière-plan automatiquement géré par retrofit. Execute - Fonctionne sur le thread d'interface utilisateur manuellement requis pour mettre dans le thread d'arrière-plan ou prendre l'aide de la tâche asynchrone.

2
Rahul Jain