Java 改造 |在 lambda 表达式中调用方法的 return

Java Retrofit | Calling a method's return in a lambda expression

假设我有这段代码

public String userName(){
//Retrofit setup here 
MyAPI service = retrofit.create(MyAPI.class);
 Call<Users> call = service.getUser();
            call.enqueue(new Callback<>() {
                @Override
                public void onResponse(Call<Users> call, Response<Users> response) {
                  //suppose I get what I want here:
                  response.body().getUserName();
                }

                @Override
                public void onFailure(Call<Users> call, Throwable throwable) {
                   //let's just say we return "User not found" onFailure
                }
            });
//return statement here
}

有没有办法让 userName() 方法的 String return 语句出现在 lambda 表达式中?如果没有,我可以使用什么最简单的方法(处理量最少)来实现这一点。

Retrofit 有一个 isExecuted 调用方法,所以我考虑在 while 循环中使用它。但我只是想知道在我继续之前是否有更简单的方法来做到这一点。 谢谢。

不,那是不可能的。 enqueue 表示:异步执行此操作。就像,不是现在,以后。

你在哪里写的return statement here?在 onResponse/onFailure 方法之前 运行s,所以你不能 'move' 那里的 return 语句 - 你的方法必须 return (因此,知道什么到 return) 在你想要 return 语句的地方甚至有 运行,这使得那不可能。

这是异步的问题API:他们很讨厌编写代码。当您说 'callback hell' 时,这就是人们在谈论的内容:您需要重新设计所有代码,以便该方法不需要 return 任何东西;相反,所有作用于 return 值的代码都需要打包在一个 lambda 中并传送到这个方法,这样你就可以调用那个 lambda(并将你想要的东西传递给 return,例如 "User not found",作为参数代替)。

这里可能有不使用入队的方法,我会先看一下。

当然可以。您可以创建一个适用于任何请求的通用回调 class,而不是使用匿名回调 class。

private class RetroCallback<T> implements  Callback<T>{
        private Consumer<Response<T>> acceptFn;

        public RetroCallback(Consumer<Response<T>> acceptFn){
            this.acceptFn = acceptFn;
        }

        @Override
        public void onResponse(Call<T> call, Response<T> response) {
            Log.d(LOG_TAG, "Request was: " + call.request().toString());
            if(response.isSuccessful()){
                Log.d(LOG_TAG, "Response SUCCESS: " + response.toString());
            }else{
                Log.d(LOG_TAG, "Response FAILED: " + response.toString());
                //TODO: print error message or similar
                return;
            }

            //TODO: Do stuff that you would normally do on every callback, e.g. print message of "payload DTO" or similar

            // Call the lambda
            if(acceptFn != null)
                acceptFn.accept(response);
        }

        @Override
        public void onFailure(Call<T> call, Throwable t) {
            Log.d(LOG_TAG, "Request failed: " + call.request().toString() + " -> " + t.getMessage());
            //TODO: Do your error handling
        }
    }

然后: 在定义回调 class 之后,您仍然需要为您的网络服务调用添加额外的包装器。这些包装器会生成一些额外的 boiletplate-code,但是我更喜欢在定义的上下文中使用样板代码,而不必在我的项目中到处处理它:

public void getAllCustomer(final Consumer<Response<List<CustomerDTO>>> onResponseFn){
        customerController.getAllCustomer().enqueue(new RetroCallback(onResponseFn));
    }

并使用干净的 lambda 在代码中的任何位置调用该方法:

WebController.with(getApplicationContext()).getAllCustomer(payloadDtoResponse -> {
            if (payloadDtoResponse.isSuccessful()) {
                //TODO: Do your stuff
            }
        });

: 如果您不想添加这些包装器,只需直接调用入队方法并使用您的 lambda 传递 RetroCallback:

WebController.with(getApplicationContext()).customerController.getAllCustomer().enqueue(new RetroCallback(responseDto ->
    {
         //YOUR CODE...
    }
));