【问题标题】:How to get async call to return response to main thread, using okhttp?如何使用okhttp获取异步调用以返回对主线程的响应?
【发布时间】:2018-10-12 20:57:17
【问题描述】:

我正在尝试为 Android 制作一个程序,并且我正在使用 okhttp 进行 json 调用。 我真的很想将我的回复返回到我正在创建的线程之外。我需要为异步调用创建线程,否则我会得到 NetworkOnMainThreadException。问题是我似乎无法在“onResponse”方法之外获取我的响应字符串,即使我的 responseString 是类中的全局变量。由于它是异步的,因此线程在返回之前不会及时运行以在全局变量中获取我的值。如何确保在响应返回我的 responseString 值之前获得响应?

这是我的代码:

public static String getUserProductCategoriesFromServer(Activity activity, final String UID, final String EXPIRY, final String CLIENT, final String ACCESSTOKEN)
{
    activity.runOnUiThread(new Runnable()
    {
        @Override
        public void run()
        {
            final OkHttpClient client = new OkHttpClient();
            final Request request = new Request.Builder()
                    .url(JsonStorage.getJsonUserProductCategories())
                    .get()
                    .addHeader("access-token", ACCESSTOKEN)
                    .addHeader("client", CLIENT)
                    .addHeader("expiry", EXPIRY)
                    .addHeader("uid", UID)
                    .build();



            client.newCall(request).enqueue(new Callback()
            {
                @Override
                public void onFailure(Call call, IOException e)
                {

                }

                @Override
                public void onResponse(Call call, Response response) throws IOException
                {
                    try
                    {
                        response = client.newCall(request).execute();
                        String json = response.body().string();
                        JSONObject jsonObject = new JSONObject(json);
                        JSONArray jsonData = (JSONArray) jsonObject.getJSONArray("user_product_category_names");
                        responseString = jsonData.toString();
                        Log.v("TEST1", jsonData.toString()); //RETURNS JSON :D
                        Log.v("TEST2", responseString); //RETURNS JSON :D
                    } catch (IOException | JSONException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    });
    Log.v("TEST3", responseString); //RETURNS "NULL" :(
    return responseString;
}

【问题讨论】:

  • 您可以返回 Call 并将结果排入您的 ui 组件,也可以创建帮助函数来序列化您的 json 数据,或者您可以使用 gson
  • 您可以为响应后要执行的下一个任务创建更多函数,并在您的 onResponse 方法中调用这些方法

标签: java android json asynchronous okhttp


【解决方案1】:

从异步世界到同步(基于线程)获取结果的常用方法是使用Futures。许多库都实现了这样的接口,例如番石榴。标准 java 具有名为 CompletableFuture 的实现。它使用具有不同名称和签名的方法,但可以轻松实现适配器:

class CallbackFuture extends CompletableFuture<Response> implements Callback {
    public void onResponse(Call call, Response response) {
         super.complete(response);
    }
    public void onFailure(Call call, IOException e){
         super.completeExceptionally(e);
    }
}

那么你可以如下使用它:

CallbackFuture future = new CallbackFuture();
client.newCall(request).enqueue(future);
Response response = future.get();

拥有Response,您可以像在第一个变体中那样提取responseString

【讨论】:

  • 谢谢!详细说明其他人是否遇到此问题:由于我支持 API 23,并且 CompletableFuture 可从 API 24+ 获得,我使用了 streamsupport-cfuture 库,它是此功能的反向移植(我认为它一直支持到API 16)。因为我使用了这个自定义回调,所以我可以在主线程上运行它,并且我不再像 okhttp3 在我使用它们的实现时给我的那样得到 NetworkOnMainThreadException。谢谢你!
猜你喜欢
  • 2014-08-06
  • 2016-01-06
  • 2022-01-19
相关资源
最近更新 更多