2016-12-05 125 views
-1

我使用的庫retrofit-2.1.0Retrofit2異步回調不叫

public class UserManager { 
    private static final Retrofit retrofit = new Retrofit.Builder() 
      .baseUrl(MY_URL) 
      .addConverterFactory(GsonConverterFactory.create()) 
      .build(); 
    private static final UserService service = retrofit.create(UserService.class); 

    public static User getUserById(Integer userId) { 
     Call<User> call = service.getUser(userId); 
     final User[] user = new User[1]; 
     final boolean[] isCalled = {false}; 

     call.enqueue(new Callback<User>() { 
      @Override 
      public void onResponse(Call<User> call, Response<User> response) { 
       System.err.println("CALLED"); 
       user[0] = response.body(); 
       isCalled[0] = true; 
      } 

      @Override 
      public void onFailure(Call<User> call, Throwable t) { 
       isCalled[0] = true; 
      } 
     }); 
     return user[0]; 
    } 

    interface UserService { 
     @GET("users/{user_id}") 
     Call<User> getUser(@Path("user_id") Integer userId); 
    } 
} 

我從JUnit4測試調用它有這個非常簡單的代碼。

public class UserManagerTest { 
    @Test 
    public void testGetBattleById() throws Exception { 
     User user = UserManager.getUserById(1); 
    } 
} 

User類是罰款和GSON是能夠序列JSON進去。網址也很好。

問題既不是onResponse也不是onFailure實際上被調用。 isCalled[0]仍然falseuser[0]仍然null,我沒有看到任何stderr。

我GOOGLE了這個問題,發現了一些非常相似的情況,但不幸的是沒有真正的解決方案。我究竟做錯了什麼?

+2

[這就是所謂的(http://ideone.com/PPHi95),但不那麼,你想... – Selvin

+0

後調用權限,您無法返回用戶...它總是會返回null,因爲請求是異步的,並且你正在以同步的方式使用它 – Jaythaking

回答

2

在這樣的方法不能返回結果。您需要等待兩個回調中的任何一個,然後有一個接口將結果發送到調用方法。 這是因爲enqueue方法是異步的,調用方法後無法直接得到結果。

喜歡的東西

public interface OnGetUserCallback { 
    void onGetUser(User user); 

    void onError(Throwable t); 
} 

public static void getUserById(Integer userId, OnGetUserCallback onGetUserCallback) { 
    Call<User> call = service.getUser(userId); 

    call.enqueue(new Callback<User>() { 
     @Override 
     public void onResponse(Call<User> call, Response<User> response) { 
      onGetUserCallback.onGetUser(response.body()); 
     } 

     @Override 
     public void onFailure(Call<User> call, Throwable t) { 
      onGetUserCallback.onError(t); 
     } 
    }); 
} 
+0

你真的需要你自己的接口?使用提供的'回調'作爲參數 –

+0

您不必這樣做,但我不會像這樣傳遞迴調對象本身。有了這樣的回調,接口使事情變得更加清晰。由於我們可以壓制UserManager的整個執行過程,但界面會相同。就像更改網絡庫或更改數據源本身一樣。 –

2

您正在使用排隊在同步方式,這將始終返回你因爲請求尚未完成,當您返回嘗試這種方式只是爲了看看如果多數民衆贊成工作:

User user = call.execute(); 

如果您想要使用異步功能,則需要在請求完成時觸發某種BroadcastReceiver,以通知視圖現在檢索到數據。您也可以爲此使用EventBus

而且你想分配UserBattle對象...

+4

這顯然會導致NetworkOnMainThreadException ... **編輯:**不需要使用BroadcastReceiver和EventBus ......足夠了:是將代碼移動到onResponse ... – Selvin

+1

感謝您的答案。將'User'分配給'Battle'只是一個錯字。我嘗試使用同步調用,但我有這個異常,並決定嘗試在異步中使用'retrofit'是因爲我不想打擾線程。 – Qumeric

+0

如果你使用同步調用,它實際上並不像線程那麼複雜......你能在這裏發佈你得到的異常嗎? – Jaythaking