Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

android - 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 ?
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

onResponse is asynchronous so it will most probably finish after revealCourtPlace has returned.

You cannot return anything from inside onResponse like that. You can however, pass the value up or restructure your code to work with something like 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

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. 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.

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. 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. This is an Rx observable that emits only one item or errors. The type should also be something else than JsonObject, but this is quite hard to tell from your code what should it be. Anyway, this will work too.

The next step is to simply return the result from your revealCourtPlace method:

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. 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.

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:

revealCourtPlace("some court id", this);

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...