
在android平台上,所有耗时的操作(如网络请求、文件i/o等)都禁止在主线程(ui线程)上执行,以避免造成anr(application not responding)错误,从而提升用户体验。okhttpclient默认提供了两种执行网络请求的方式:
当我们需要在一个子Activity中发起网络请求,并期望在请求完成后才将数据返回给父Activity时,直接使用enqueue()会导致子Activity在网络请求完成前就返回,因为enqueue()是非阻塞的。而尝试在主线程中调用execute()则会立即触发android.os.NetworkOnMainThreadException。
为了解决上述问题,我们可以在一个后台线程中发起异步网络请求,并利用java.util.concurrent.CountDownLatch机制来同步等待请求的完成。CountDownLatch是一个同步辅助类,它允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。
CountDownLatch工作原理:
实现步骤:
示例代码:
假设我们有一个SecondaryActivity,它需要从REST API获取数据,并在数据获取后才关闭并返回结果。
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class SecondaryActivity extends AppCompatActivity {
private String apiResponseData = null; // 用于存储网络请求结果
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_secondary); // 假设有一个布局
// 在后台线程中执行网络请求和等待逻辑
new Thread(new Runnable() {
@Override
public void run() {
performNetworkRequestAndWait();
// 网络请求完成后,可以在这里处理数据并关闭Activity
// 注意:UI操作仍需回到主线程
runOnUiThread(new Runnable() {
@Override
public void run() {
if (apiResponseData != null) {
// 处理获取到的数据,例如更新UI或设置结果
System.out.println("Received data: " + apiResponseData);
// 示例:设置结果并关闭Activity
// Intent resultIntent = new Intent();
// resultIntent.putExtra("data", apiResponseData);
// setResult(RESULT_OK, resultIntent);
// finish();
} else {
System.out.println("Failed to retrieve data.");
// setResult(RESULT_CANCELED);
// finish();
}
}
});
}
}).start();
}
private void performNetworkRequestAndWait() {
// 创建一个CountDownLatch,计数器为1
CountDownLatch latch = new CountDownLatch(1);
OkHttpClient client = new OkHttpClient();
// 假设someRequest是一个JSON字符串
String someRequest = "{ \"key\": \"value\" }";
RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), someRequest);
String myURL = "https://api.example.com/data"; // 替换为你的API地址
Request request = new Request.Builder().url(myURL).post(body).build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
System.err.println("Network request failed: " + e.getMessage());
apiResponseData = null; // 请求失败,数据为空
latch.countDown(); // 无论成功失败,都要释放latch
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
if (response.isSuccessful() && response.body() != null) {
apiResponseData = response.body().string();
System.out.println("Network response: " + apiResponseData);
} else {
System.err.println("Network request unsuccessful: " + response.code());
apiResponseData = null;
}
latch.countDown(); // 无论成功失败,都要释放latch
}
});
try {
// 等待网络请求完成,最多等待10秒
// await()方法会阻塞当前线程,直到latch.countDown()被调用或超时
boolean completed = latch.await(10, TimeUnit.SECONDS);
if (!completed) {
System.err.println("Network request timed out.");
apiResponseData = null; // 超时,数据为空
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 重新设置中断状态
System.err.println("Waiting for network request was interrupted: " + e.getMessage());
apiResponseData = null; // 中断,数据为空
}
// 在此处,apiResponseData变量将包含网络请求的结果(如果成功且未超时)
// 或者为null(如果失败、超时或中断)
}
}代码解析:
CountDownLatch提供了一种简单而有效的机制,用于在Android后台线程中同步等待OkHttpClient异步网络请求的结果。通过在请求回调中释放锁,并在另一个线程中阻塞等待,我们可以确保依赖网络数据的逻辑在数据可用后才执行,同时避免了NetworkOnMainThreadException和ANR。正确地结合线程管理、超时和错误处理,可以构建出健壮且响应迅速的Android应用。
以上就是Android中同步等待OkHttpClient网络请求的有效策略的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号