android 框架—网络访问Okhttp
下面给出一份 最新、可直接拷贝运行 的 Android OkHttp 基本使用速查表,
覆盖“依赖 → 权限 → 常用 GET/POST/上传 → 同步/异步 → 线程模型 → 踩坑”6 大环节,
依赖 & 权限(一次到位)
依赖
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
权限
<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- Android 9+ 允许 http 明文(开发阶段)-->
<application android:usesCleartextTraffic="true" ... >
全局单例工具类(线程安全)
public final class HttpUtil {private static final OkHttpClient CLIENT = new OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS).readTimeout(20, TimeUnit.SECONDS).writeTimeout(20, TimeUnit.SECONDS).addInterceptor(chain -> { // 极简日志拦截器Request req = chain.request();Log.d("OKHTTP", req.method() + " " + req.url());return chain.proceed(req);}).build();public static OkHttpClient client() { return CLIENT; }
}
GET 请求(异步)
public static void getAsync(String url, Callback cb) {Request req = new Request.Builder().url(url).get().build();HttpUtil.client().newCall(req).enqueue(cb);
}/* 使用 */
getAsync("https://api.github.com/users/google", new Callback() {@Override public void onFailure(@NonNull Call call, @NonNull IOException e) {Log.e("OKHTTP", "get error", e);}@Override public void onResponse(@NonNull Call call, @NonNull Response resp) throws IOException {if (resp.isSuccessful()) {String body = resp.body().string();Log.i("OKHTTP", "get body=" + body);}}
});
POST 表单(application/x-www-form-urlencoded)
public static void postFormAsync(String url, Map<String,String> params, Callback cb) {FormBody.Builder fb = new FormBody.Builder();for (Map.Entry<String,String> e : params.entrySet()) fb.add(e.getKey(), e.getValue());Request req = new Request.Builder().url(url).post(fb.build()).build();HttpUtil.client().newCall(req).enqueue(cb);
}
POST JSON(application/json)
public static void postJsonAsync(String url, String json, Callback cb) {RequestBody body = RequestBody.create(json, MediaType.parse("application/json; charset=utf-8"));Request req = new Request.Builder().url(url).post(body).build();HttpUtil.client().newCall(req).enqueue(cb);
}
文件上传(Multipart,带进度)
public static void uploadAsync(String url, File file, Callback cb) {RequestBody fileBody = RequestBody.create(file, MediaType.parse("application/octet-stream"));MultipartBody body = new MultipartBody.Builder().setType(MultipartBody.FORM).addFormDataPart("file", file.getName(), fileBody).addFormDataPart("key", "extra") // 可继续加字段.build();Request req = new Request.Builder().url(url).post(body).build();HttpUtil.client().newCall(req).enqueue(cb);
}
下载文件(带进度,Kotlin 版更简洁,这里给 Java)
public static void downloadAsync(String url, File saveFile, ProgressListener listener, Callback cb) {Request req = new Request.Builder().url(url).build();OkHttpClient downClient = HttpUtil.client().newBuilder().addNetworkInterceptor(chain -> {Response original = chain.proceed(chain.request());return original.newBuilder().body(new ProgressResponseBody(original.body(), listener)).build();}).build();downClient.newCall(req).enqueue(cb);
}/* 进度回调 */
public interface ProgressListener {void update(long bytesRead, long contentLength, boolean done);
}/* 包装 ResponseBody 计算进度 */
private static class ProgressResponseBody extends ResponseBody {private final ResponseBody delegate;private final ProgressListener listener;ProgressResponseBody(ResponseBody d, ProgressListener l) { delegate = d; listener = l; }@Override public long contentLength() { return delegate.contentLength(); }@Override public MediaType contentType() { return delegate.contentType(); }@Override public BufferedSource source() {return Okio.buffer(new ForwardingSource(delegate.source()) {long total = 0L;@Override public long read(Buffer sink, long byteCount) throws IOException {long bytes = super.read(sink, byteCount);total += (bytes != -1 ? bytes : 0);listener.update(total, contentLength(), bytes == -1);return bytes;}});}
}
同步调用(不推荐主线程,仅给单元测试)
public static String getSync(String url) throws IOException {Request req = new Request.Builder().url(url).get().build();try (Response resp = HttpUtil.client().newCall(req).execute()) {if (!resp.isSuccessful()) throw new IOException("code=" + resp.code());return resp.body().string();}
}
注意事项(面试常问)
所有
onResponse
回调不在主线程,若更新 UI 记得runOnUiThread()
/Handler
/LiveData.postValue()
。ResponseBody.string()
只能读一次,再读需要cache()
或自己缓存。Android 9+ 默认禁止 HTTP 明文,需在
AndroidManifest.xml
加android:usesCleartextTraffic="true"
或配置networkSecurityConfig
。上传/下载大文件用
@Streaming
+MultipartBody
边读边写,防止 OOM。
“先 client 后 request,enqueue 异步 execute 同步;
FormBody 表单,RequestBody JSON,Multipart 传文件;
回调非 UI 线程,刷新界面要切换!”