【问题标题】:How do I await Retrofit async web service call? (call.enqueue)如何等待 Retrofit 异步 Web 服务调用? (call.enqueue)
【发布时间】:2018-02-17 04:34:42
【问题描述】:

我是 java/android 新手,之前在 C# 中使用异步调用做了很多工作,我可以使用 await 来强制响应,然后再转到更多代码。

据我所知, call.enqueue 是异步的,但我希望等待它,以便我的 LoginActivity 方法可以根据登录是否成功来处理后续步骤。

我做了一些日志,理想情况下应该显示如下:

FIRST
SECOND
THIRD
FOURTH

但是由于异步,我反而得到:

FIRST
SECOND
FOURTH
THIRD

LoginActivity.java

public boolean tryLoginAttempt(LoginRequest request) {
    // Call login service, login method
    LoginService service = new LoginService();

    Log.d(TAG, "FIRST");

    LoginResponse loginResponse = service.loginMethod(request); // ** want to await this

    Log.d(TAG, "FOURTH");

    // If login works, navigate to tabbed menu
    if (loginResponse.getAuthorized()) {
        Intent intent = new Intent(LoginActivity.this, SelectTeamActivity.class);
        startActivity(intent);
    }

    return loginResponse.getAuthorized();
}

LoginService.java

LoginResponse mLoginResponse = new LoginResponse();

public LoginResponse loginMethod(LoginRequest request) {
    try {
        String baseUrl = "https://myurl.com";
        // Create retrofit object
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .build();   //  This instantiates the Retrofit builder we will need for REST calls

        LoginEndpointInterface apiService = retrofit.create(LoginEndpointInterface.class);

        // Call the login method
        Observable<LoginResponse> call = apiService.login(request);

        Log.d(TAG, "SECOND");

        call.enqueue(new Callback<LoginResponse>() { // ** running as async
            @Override
            public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
                Log.d(TAG, "THIRD");

                int statusCode = response.code();

                // Login worked
                if (response.body().getAuthorized()) {
                    Log.d(TAG, "Login worked");
                    mLoginResponse = response.body();
                } else {
                    Log.d(TAG, "Login failed");
                }
            }

            @Override
            public void onFailure(Call<LoginResponse> call, Throwable t) {
                Log.d(TAG, "ERROR in web service call: " + t.toString());
            }
        });
    Log.d(TAG, "returning result of login check: " + result);
    } catch(Exception ex) {
        ex.printStackTrace();
    }

    return mLoginResponse;
}

改造调用接口

public interface LoginEndpointInterface {

    @POST("api/login/")
    retrofit2.Call<LoginResponse> login(@Body LoginRequest body);

}

感谢您的帮助!

【问题讨论】:

  • 所以这段代码运行良好。使用 retrofit.enqueue 调用是异步完成的,并且每当从 BE 返回某些内容时都会执行回调。您的其他代码将继续执行。如果您想等到某些事情回来,您应该使用call.execute,因为它是同步完成的。参考:square.github.io/retrofit/2.x/retrofit/retrofit2/…

标签: java android retrofit retrofit2


【解决方案1】:

在android中,阻塞用户界面的网络或繁重的任务不能在主线程上完成,因此所有这些事情都是异步完成的。 要实现您正在尝试的内容,您需要在网络调用完成后调用所有后续步骤,这只能在 onResponseonFailure 内的改造回调中完成。它基本上是调用链。为了使您的代码更具可读性,您可以使用自己的接口来实现回调机制,或者您可以使用 RxJava 之类的库,这使得代码变得非常简单。

【讨论】:

    猜你喜欢
    • 2011-12-21
    • 1970-01-01
    • 2016-09-04
    • 1970-01-01
    • 1970-01-01
    • 2016-05-27
    • 1970-01-01
    • 2023-03-15
    相关资源
    最近更新 更多