简体   繁体   English

如何从Retrofit v2的onResponse返回值

[英]How can I return value from onResponse of Retrofit v2

I want to return a string value from my function. 我想从我的函数返回一个字符串值。 But I do not know how to handle it? 但我不知道如何处理它? I tried final one-array solution but it did not work out. 我尝试了最终的单阵列解决方案,但它没有成功。

Here is my code: 这是我的代码:

public String revealCourtPlace(String courtID)
{

    BaseService.getInstance().getUniqueCourt(Session.getToken(),courtID).enqueue(new Callback<JsonObject>()
    {
        @Override
        public void onResponse(Call<JsonObject> call, Response<JsonObject> response)
        {

            JsonObject object = response.body();
            boolean success = object.get("success").getAsBoolean(); //json objesinde dönen success alanı true ise
            if (success)
            {
                JsonArray resultArray = object.get("data").getAsJsonObject().get("result").getAsJsonArray();
                for (int i = 0; i < resultArray.size(); i++)
                {
                    JsonObject jsonInfoResult = resultArray.get(i).getAsJsonObject();
                    String courtName=jsonInfoResult.get("name").getAsString();
                }

            }

        }

        @Override
        public void onFailure(Call<JsonObject> call, Throwable t)
        {

        }

    });

    //return ?
}

onResponse is asynchronous so it will most probably finish after revealCourtPlace has returned. onResponse是异步的,因此很可能在revealCourtPlace返回后完成。

You cannot return anything from inside onResponse like that. 你不能从内返回任何onResponse这样。 You can however, pass the value up or restructure your code to work with something like Rx. 但是,您可以传递值或重构代码以使用Rx之类的东西。

Let me explain. 让我解释。 So, one option is to pass the string value you want up with a callback. 因此,一个选项是通过回调传递您想要的字符串值。 Say you have the interface: 假设您有界面:

public interface RevealCourtPlaceCallbacks {
     void onSuccess(@NonNull String value);

     void onError(@NonNull Throwable throwable);
}

These are the methods that whoever wants to receive the value of your network call will have to implement. 这些方法是任何想要接收网络呼叫价值的人必须实施的方法。 You use this for example by passing it to the method revealCourtPlace 例如,您可以将其传递给revealCourtPlace方法

public void revealCourtPlace(String courtID, @Nullable RevealCourtPlaceCallbacks callbacks)
{  
   BaseService.getInstance()
      .getUniqueCourt(Session.getToken(),courtID)
      .enqueue(new Callback<JsonObject>() {
    @Override
    public void onResponse(Call<JsonObject> call, Response<JsonObject> response)
    {

        JsonObject object = response.body();
        boolean success = object.get("success").getAsBoolean(); //json objesinde dönen success alanı true ise
        if (success)
        {
            JsonArray resultArray = object.get("data").getAsJsonObject().get("result").getAsJsonArray();
            for (int i = 0; i < resultArray.size(); i++)
            {
                JsonObject jsonInfoResult = resultArray.get(i).getAsJsonObject();
                String courtName=jsonInfoResult.get("name").getAsString();

                if (callbacks != null)
                  calbacks.onSuccess(courtName);
            }

        }

    }

    @Override
    public void onFailure(Call<JsonObject> call, Throwable t)
    {
        if (callbacks != null)
            callbacks.onError(t);
    }

  });
}

Important things to notice: The method returns void. 需要注意的重要事项:该方法返回void。 You pass the callbacks as an argument. 您将回调作为参数传递。 These callbacks must be implemented by who's calling the method, or as an anonymous class implemented on the calling spot. 这些回调必须由调用该方法的人或作为在调用点上实现的匿名类来实现。

This enables you to receive the string courtName asynchronously and not having to worry about returning a value. 这使您可以异步接收字符串courtName ,而不必担心返回值。

There's another option where you could make your code reactive. 还有另一个选项可以让您的代码被动反应。 This is a bit more work and a shift in paradigm. 这是一项更多的工作和范式的转变。 It also requires knowledge in Rx java. 它还需要Rx java中的知识。 I'll leave here an example of how this can be done. 我将在这里留下一个如何做到这一点的例子。 Bear in mind that there are several ways of doing this. 请记住,有几种方法可以做到这一点。

First you should define the retrofit interface differently. 首先,您应该以不同方式定义改造界面。 The return type must now be an observable: 返回类型现在必须是可观察的:

public interface CourtApiClient {
    @GET(/*...*/)
    Single<JsonObject> getUniqueCourt(/*...*/);
}

I don't really know the entire interface details of your call, but the important part here is the return type is now Single . 我真的不知道你的调用的整个接口细节,但这里的重要部分是返回类型现在是Single This is an Rx observable that emits only one item or errors. 这是一个Rx observable,只发出一个项目或错误。 The type should also be something else than JsonObject , but this is quite hard to tell from your code what should it be. 该类型也应该是JsonObject以外的其他类型,但是很难从代码中分辨出它应该是什么。 Anyway, this will work too. 无论如何,这也会奏效。

The next step is to simply return the result from your revealCourtPlace method: 下一步是简单地从revealCourtPlace方法返回结果:

public Single<JsonObject> revealCourtPlace(String courtID, @Nullable RevealCourtPlaceCallbacks callbacks)
{  
   return BaseService.getInstance()
      .getUniqueCourt(Session.getToken(),courtID);
}

The key difference here is that the method now returns the observable and you can subscribe to it whenever you want. 这里的关键区别是该方法现在返回observable,您可以随时订阅它。 This makes the flow seem synchronous although it's in fact asynchronous. 这使得流看起来是同步的,尽管它实际上是异步的。

You have now the choice to either map the JsonObject to the several strings you want, or to do the parsing in your subscriber. 您现在可以选择将JsonObject映射到您想要的几个字符串,或者在您的订阅者中进行解析。

Edit 编辑

Since you asked in the comments how you can call your function here's a possibility: 由于您在评论中询问如何调用您的函数,这是一种可能性:

revealCourtPlace("some court id", new RevealCourtPlaceCallbacks() {
       @Override
       public void onSuccess(@NonNull String value) {
          // here you use the string value
       }

       @Override
       public void onError(@NonNull Throwable throwable) {
          // here you access the throwable and check what to do
       }
  });

Alternatively you can make the calling class implement these callbacks and simply pass this : 或者你可以调用的类实现这些回调和简单地传递this

revealCourtPlace("some court id", this);

With retrofit2 is possible make synchronous call: 使用retrofit2可以进行同步调用:

Callback<JsonObject> callback = BaseService.getInstance().getUniqueCourt(Session.getToken(),courtID)
Response<JsonObject> response = callback.execute();
...

however, synchronous requests trigger app crashes on Android 4.0 or newer. 但是,同步请求会在Android 4.0或更高版本上触发应用程序崩溃。 You'll run into the NetworkOnMainThreadException error. 您将遇到NetworkOnMainThreadException错误。

More information here . 更多信息在这里

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM