You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从OkHttpClient的方法中返回String类型响应?

解决OkHttpClient异步请求无法获取返回值的问题

你遇到的问题核心在于OkHttpClient的enqueue()是异步请求:它会在后台线程执行网络操作,而你在调用teste.Request()后立刻调用teste.getResponse()时,网络请求还未完成,response字段仍为初始的null,所以Toast显示空值。

以下是几种可行的解决方案:


方案一:自定义回调接口(基础异步处理)

修改Teste类,通过自定义回调接口在请求完成时通知调用方:

import java.io.IOException;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;

public class Teste {

    private final OkHttpClient client = new OkHttpClient();

    // 定义请求完成的回调接口
    public interface OnRequestCompletedListener {
        void onSuccess(String response);
        void onFailure(String errorMsg);
    }

    public void request(String url, FormBody formBody, OnRequestCompletedListener listener) {
        Request request = new Request.Builder()
                .url(url)
                .post(formBody)
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override 
            public void onFailure(Call call, IOException e) {
                if (listener != null) {
                    listener.onFailure(e.getMessage());
                }
            }

            @Override 
            public void onResponse(Call call, Response response) throws IOException {
                try (ResponseBody responseBody = response.body()) {
                    if (!response.isSuccessful()) {
                        String errorMsg = "Unexpected code " + response;
                        if (listener != null) {
                            listener.onFailure(errorMsg);
                        }
                        return;
                    }

                    if (listener != null) {
                        listener.onSuccess(responseBody.string());
                    }
                }
            }
        });
    }
}

在MainActivity中调用时,通过回调接收结果(注意切换到主线程更新UI):

Teste teste = new Teste();

teste.request("http://127.0.0.1/teste.php", new FormBody.Builder()
                .add("fname", "teste")
                .build(), new Teste.OnRequestCompletedListener() {
            @Override
            public void onSuccess(String response) {
                runOnUiThread(() -> {
                    Toast.makeText(MainActivity.this, response, Toast.LENGTH_SHORT).show();
                });
            }

            @Override
            public void onFailure(String errorMsg) {
                runOnUiThread(() -> {
                    Toast.makeText(MainActivity.this, errorMsg, Toast.LENGTH_SHORT).show();
                });
            }
        });

方案二:改用同步请求(需在子线程执行)

如果需要类似同步的方式获取结果,可以使用execute()同步调用,但必须放在子线程中(Android主线程不允许网络操作):

修改Teste类的请求方法:

public String request(String url, FormBody formBody) throws IOException {
    Request request = new Request.Builder()
            .url(url)
            .post(formBody)
            .build();

    try (Response response = client.newCall(request).execute()) {
        if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
        return response.body().string();
    }
}

在MainActivity中调用:

Teste teste = new Teste();

new Thread(() -> {
    try {
        String response = teste.request("http://127.0.0.1/teste.php", new FormBody.Builder()
                .add("fname", "teste")
                .build());
        // 切换到主线程显示Toast
        runOnUiThread(() -> {
            Toast.makeText(MainActivity.this, response, Toast.LENGTH_SHORT).show();
        });
    } catch (IOException e) {
        runOnUiThread(() -> {
            Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
        });
    }
}).start();

方案三:使用Kotlin协程(Kotlin项目推荐)

如果项目支持Kotlin,协程可以简化异步逻辑,避免回调嵌套:

Teste类(Kotlin版本):

import okhttp3.FormBody
import okhttp3.OkHttpClient
import okhttp3.Request
import java.io.IOException

class Teste {
    private val client = OkHttpClient()

    suspend fun request(url: String, formBody: FormBody): String {
        return kotlin.runCatching {
            val request = Request.Builder()
                .url(url)
                .post(formBody)
                .build()
            client.newCall(request).execute().use { response ->
                if (!response.isSuccessful) throw IOException("Unexpected code ${response}")
                response.body?.string() ?: throw IOException("Empty response body")
            }
        }.getOrThrow()
    }
}

MainActivity中调用:

lifecycleScope.launch {
    try {
        val teste = Teste()
        val response = teste.request("http://127.0.0.1/teste.php", FormBody.Builder()
            .add("fname", "teste")
            .build())
        Toast.makeText(this@MainActivity, response, Toast.LENGTH_SHORT).show()
    } catch (e: IOException) {
        Toast.makeText(this@MainActivity, e.message, Toast.LENGTH_SHORT).show()
    }
}

关键注意点

  1. 异步请求不能在调用后立刻获取结果,必须等待请求完成后通过回调/协程接收
  2. Android中网络请求必须在子线程执行,更新UI必须切换回主线程
  3. 优先推荐回调接口或协程的方式,符合异步编程的最佳实践

内容的提问来源于stack exchange,提问作者Fábio Monteiro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 09:10:40