2016-12-05 124 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