准备工作 简单创建 GET请求 POST请求 下载(显示进度) 上传(显示进度) 其他 复制代码
OkHttp是一个处理网络请求的开源项目; 安卓端轻量级框架; 用于替代HttpUrlConnection和Apache HttpClient;
//网络请求OkHttp3 implementation 'com.squareup.okhttp3:okhttp:4.3.1' 复制代码
<uses-permission android:name="android.permission.INTERNET" /> 复制代码
API级别28或更高级别手机,在http请求时(非Https请求)会有错误提示,并且请求不到数据。
CLEARTEXT communication to www.baidu.com not permitted by network security policy 复制代码
需要在AndroidManifest的application中设置android:usesCleartextTraffic="true"
okhttp提供有同步、异步两种请求方式,差别不大 同步请求时在请求过程中线程处于堵塞状态,不建议放在主线程中运行,容易出现ANR(Application Not responding)(应用程序没有响应)。
1、创建OkHttpClient对象 2、通过Builder模式创建Request对象 3、通过request的对象去构造得到一个Call对象 4、执行请求,调用call.enqueue()执行异步请求,调用call .execute()执行同步请求 复制代码
OkHttpClient client = new OkHttpClient(); //实例化OkHttpClient 对象 Request request = new Request.Builder() //创建Request对象的Builder模式 .url("http://www.baidu.com") //设置访问的网址 //.get() //设置为GET请求 默认为GET请求,可以忽略 .build(); //创建Request对象 Call call = client.newCall(request); //通过request的对象去构造得到一个Call对象 call.enqueue(new Callback() { //调用call的enqueue(),进行异步请求 @Override public void onFailure(Call call, IOException e) { //错误回调,通过e.getMessage()可以拿到错误信息 Log.d("onFailure","onFailure: "+e.getMessage()); } @Override public void onResponse(Call call, Response response) throws IOException { //成功回调,在这里我们可以拿到服务器返回的数据 Log.d("onResponse","onResponse: "+response.body().string()); } }); 复制代码
OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url("http://www.baidu.com") .get() .build(); Call call = client.newCall(request); Response response = null; try { response = call .execute();//调用call的execute()进行同步请求,在请求过程中处于堵塞状态,建议写在子线程中 Log.d("onResponse","onResponse: "+response.body().string()); } catch (IOException e) { e.printStackTrace(); Log.d("onFailure", "onFailure: "+e.getMessage()); } 复制代码
onResponse回调有一个参数是response为响应数据 如果返回的数据是字符串,可以通过response.body().string()得到 如果返回的数据是二进制字节数组,可以通过response.body().bytes()得到 如果返回的数据是inputStream,可以通过response.body().byteStream()得到 复制代码
调用call的cancel()进行中止,停止请求 call.cancel();
OkHttp支持PUT,DELETE,POST,GET等请求; 文件的上传下载 以下都使用异步请求进行
GET请求比较简单,就是上面的简单四步
OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url("") .get() .build(); Call call = client.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { } }); 复制代码
POST请求支持提交文件,流,string,表单等等 简单的POST请求(提交表单)
OkHttpClient client = new OkHttpClient(); RequestBody requestBody = new FormBody.Builder()//创建表单 .add("key","value") //传入需要提交的数据 .add("key","value") //传入需要提交的数据 .build(); //创建请求体 Request request = new Request.Builder() .url("") //设置提交数据的网址 .post(requestBody) //设置为POST请求,传入请求体 .build(); Call call = client.newCall(request); call.enqueue(new Callback() { //异步请求 @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { } }); 复制代码
其实很简单,就是GET请求或POST请求 只是将返回的数据转为流(response.body().byteStream()),再通过InputStream(), OutputStream()保存本地即可。
OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url("http://image.baidu.com/search/down?tn=download&ipn=dwnl&word=download" + "&ie=utf8&fr=result&url=http%3A%2F%2Fc.hiphotos.baidu.com%2Fzhidao%2" + "Fpic%2Fitem%2Fd009b3de9c82d1587e249850820a19d8bd3e42a9.jpg&thumburl=" + "http%3A%2F%2Fimg1.imgtn.bdimg.com%2Fit%2Fu%3D3675415932%2C4054970339%26" + "fm%3D26%26gp%3D0.jpg") //百度上的图片 .get() .build(); Call call = client.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { Log.d("onFailure", "onFailure: " + e.getMessage()); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { String path = Environment.getExternalStorageDirectory().getPath()+"/Download";//文件路径,根目录Download目录下 File file = new File(path,"image.jpg");//设置文件路劲及文件名 InputStream is = response.body().byteStream(); BufferedInputStream bis = new BufferedInputStream(is); FileOutputStream fos = new FileOutputStream(new File(path)); byte[] bytes = new byte[1024]; int len; Log.d("onResponse", "onResponse: 开始"); while ((len=is.read(bytes))!=-1){ fos.write(bytes,0,len); } fos.flush(); Log.d("onResponse", "onResponse: 结束"); is.close(); bis.close(); fos.close(); } }); 复制代码
权限获取获取SD卡的存取权限
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 复制代码
Android 6.0 注意动态授权Google在 Android 6.0 开始引入了权限申请机制,使用危险权限时需要动态的申请并得到用户的授权才能使用。存取权限属于危险权限。
如何动态获取? 这里提供一个工具类,用于动态授权
public class PermissionUtil { public static String READ_EXTERNAL_STORAGE = Manifest.permission.READ_EXTERNAL_STORAGE; //内存读取 public static String WRITE_EXTERNAL_STORAGE = Manifest.permission.WRITE_EXTERNAL_STORAGE; //内存写入 public static void getPermissions(Activity activity, String... permission) { List<String> permissions = new ArrayList<>(); //此处做动态权限申请 //判断系统是否大于等于Android 6.0 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { for(int i=0;i<permission.length;i++){ int request = ContextCompat.checkSelfPermission(activity, permission[i]); //判断是否未获取权限 if (request != PackageManager.PERMISSION_GRANTED) permissions.add(permission[i]); } if (permissions.size()>0) {//缺少权限,进行权限申请 //当前上下文;一个权限数组;一个唯一的请求码(0~65535的16位数) ActivityCompat.requestPermissions(activity, permissions.toArray(new String[permissions.size()]), 0XFF); } else { //权限同意 已全部授权 } } else { //低于api 23 不需要动态授权 } } } 复制代码
在MainActivity的onCreate()中使用,进行动态授权
PermissionUtil.getPermissions(this, PermissionUtil.READ_EXTERNAL_STORAGE, PermissionUtil.WRITE_EXTERNAL_STORAGE); 复制代码
下载一定要有下载进度的 显示下载进度有两种方法:
第一种比较简单(仅限当前可用,与其他框架联用可能会失效,如:Retrofit+OkHttp3+RxJava2联合使用时会失效,因为Retrofit的关系) 第二种有点复杂,涉及到拦截器,直接贴代码
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> <ProgressBar android:id="@+id/progressBar" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="wrap_content"/> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="下载" /> </LinearLayout> 复制代码
public class MainActivity extends AppCompatActivity { private ProgressBar progressBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //Android 6.0 及以上系统需要动态申请,PermissionUtil工具已经在上面贴出,这里进行动态申请 PermissionUtil.getPermissions(this, PermissionUtil.READ_EXTERNAL_STORAGE, PermissionUtil.WRITE_EXTERNAL_STORAGE); progressBar = findViewById(R.id.progressBar); //设置按钮点击事件 findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { download();//点击后进行下载 } }); } public void download(){ String path = Environment.getExternalStorageDirectory().getPath() + "/Download/qq.exe";//保存的路径及文件名 String url = "https://qd.myapp.com/myapp/qqteam/pcqq/PCQQ2020.exe";//这里给的是QQPC版的下载地址,文件较大 //设置下载路径和下载网址,开始下载 OkHttpHelper.getInstance().setDownloadUrl(url).startDownload(path,new OkHttpHelper.DownloadCallback() { @Override public void start(final long max) { //这里处于子线程,需返回主线程更新UI progressBar.post(new Runnable() { @Override public void run() { Toast.makeText(MainActivity.this, "开始下载", Toast.LENGTH_SHORT).show(); progressBar.setMax((int) max); } }); } @Override public void loading(final long progress) { progressBar.post(new Runnable() { @Override public void run() { progressBar.setProgress((int) progress); } }); } @Override public void complete(String msg) { } @Override public void fail(String message) { } }); } } 复制代码
public class OkHttpHelper { private OkHttpClient client; private Request request; private static OkHttpHelper instance = null; private OkHttpHelper() { initOkHttp();//初始化 } static OkHttpHelper getInstance() {//单例模式 if (instance == null) { synchronized (OkHttpHelper.class) { if (instance == null) { instance = new OkHttpHelper(); } } } return instance; } private void initOkHttp() { client = new OkHttpClient.Builder() .connectTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS) .build(); } //设置问GET请求,设置下载网址 OkHttpHelper setDownloadUrl(String url) { request = new Request.Builder() .url(url) //.header("RANGE","")//断点续传时需要使用的 .get() .build(); return this; } //设置下载路径,开始下载 public void startDownload(final String path,final DownloadCallback callback) { if (client == null) { initOkHttp(); } OkHttpClient okHttpClient = client.newBuilder().addInterceptor(new MyInterceptor(callback)).build();//插入自定义的MyInterceptor()拦截器 Call call = okHttpClient.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { callback.fail(e.getMessage()); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { download(response,path); callback.complete("完成"); } }); } //创建MyInterceptor类,实现Interceptor 拦截器 static class MyInterceptor implements Interceptor { DownloadCallback callback; public MyInterceptor(DownloadCallback callback) { super(); this.callback = callback; } @NotNull @Override public Response intercept(@NotNull Chain chain) throws IOException { Response response = chain.proceed(chain.request()); return response.newBuilder().body(new MyResponseBody(response,callback)).build(); } } //创建MyResponseBody 类,继承 ResponseBody类 static class MyResponseBody extends ResponseBody { Response response; DownloadCallback callback; MyResponseBody(Response response,DownloadCallback callback) { super(); this.response = response; this.callback = callback; } @Override public long contentLength() { //获取文件的总字节数 callback.start(response.body().contentLength()); return response.body().contentLength(); } @Nullable @Override public MediaType contentType() { //可以获取文件的类型 return response.body().contentType(); } @NotNull @Override public BufferedSource source() { contentLength(); contentType(); //可以获取文件资源 return Okio.buffer(new ForwardingSource(response.body().source()) { long bytesLength=0; @Override public long read(@NotNull Buffer sink, long byteCount) throws IOException { //获取下载进度 final long bytesRead = super.read(sink, byteCount); bytesLength += bytesRead; callback.loading(bytesLength); return bytesRead; } }); } } //注:MyResponseBody里的三个接口contentLength,contentType,source,并不会程序自己主动调用执行,需要人为被动执行; //source接口的执行,在程序执行到download方法的“InputStream is = response.body().byteStream();”时才会被调用; // 然后我们自己调用contentLength(),contentType()方法去执行, // 或者我们在download方法的“InputStream is = response.body().byteStream();”上面添加两行代码response.body().contentLength();,response.body().contentType(); //下载,执行下载、保存 public static void download(Response response,String path) throws IOException { //response.body().contentLength(); //response.body().contentType(); InputStream is = response.body().byteStream();//拿到资源,转为字节流 BufferedInputStream bis = new BufferedInputStream(is); FileOutputStream fos = new FileOutputStream(new File(path));//设置需要保存的位置,及文件 byte[] bytes = new byte[1024]; int len; while ((len = is.read(bytes)) != -1) { fos.write(bytes, 0, len);//保存 } fos.flush(); is.close(); bis.close(); fos.close(); } //一些必要的接口 public interface DownloadCallback { //各种下载需要的接口 //开始下载 void start(long max); //传入文件总字节数 //正在下载 void loading(long progress); //传入已下载的字节数 //下载完成 void complete(String msg); //传入成功信息 //请求失败 void fail( String message); //传入错误信息 } } 复制代码
注:MyResponseBody里的三个接口方法contentLength(),contentType(),source(),并不会程序自己主动调用执行,需要人为被动执行; source()的执行,是在程序执行到download方法的“InputStream is = response.body().byteStream();”时才会被调用; 然后我们自己调用contentLength(),contentType()去执行; 或者我们在download方法里添加两行代码response.body().contentLength();,response.body().contentType();,也会执行。 第一种 修改OkHttpHelper 即可
public class OkHttpHelper { private static OkHttpHelper instance = null; private OkHttpClient client; private Request request; private OkHttpHelper() { initOkHttp();//初始化 } static OkHttpHelper getInstance() {//单例模式 if (instance == null) { synchronized (OkHttpHelper.class) { if (instance == null) { instance = new OkHttpHelper(); } } } return instance; } OkHttpHelper setDownloadUrl(String url) { request = new Request.Builder() .url(url) //.header("RANGE","")//断点续传时需要使用的 .get() .build(); return this; } private void initOkHttp() { client = new OkHttpClient.Builder() .connectTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS) .build(); } void startDownload(final String path, final DownloadCallback callback) { if (client == null) { initOkHttp(); } Call call = client.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { callback.fail(e.getMessage()); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { downlaod(response, path, callback); callback.complete("完成"); } }); } public static void downlaod(Response response, String path, DownloadCallback callback) throws IOException { long max = response.body().contentLength(); callback.start(max); InputStream is = response.body().byteStream(); BufferedInputStream bis = new BufferedInputStream(is); FileOutputStream fos = new FileOutputStream(new File(path)); byte[] bytes = new byte[1024]; int len; long length = 0;//记录已下载的字节数 while ((len = is.read(bytes)) != -1) { length += len; fos.write(bytes, 0, len); callback.loading(length); } fos.flush(); is.close(); bis.close(); fos.close(); } public interface DownloadCallback { //开始下载 void start(long max);//传入文件总字节数 //正在下载 void loading(long progress);//传入已下载的字节数 //下载完成 void complete(String msg); //请求失败 void fail(String message); } } 复制代码
上传文件之前要设置上传文件的类型 例:MediaType.parse("text/plain; charset=utf-8") text/html html text/plain 文本文档 text/xml xml image/gif gif image/jpeg jpg image/png png application/xhtml-xml XHTML application/json json application/pdf pdf application/msword word文档 application/octet-stream 二进制流 复制代码
OkHttpClient client = new OkHttpClient();//实例化 //拿到上传的文件 File file = new File(Environment.getExternalStorageDirectory(),"/Download/qq.exe"); //设置上传类型 MediaType type = MediaType.parse(""); //设置请求体 RequestBody body = new MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart("","") //将文件类型和文件放入请求体 .addFormDataPart("","",RequestBody.create(file, type)) .build(); //RequestBody body = RequestBody.create(file, type); //设置上传网址(要支持上传的网址),放入请求体 Request request = new Request.Builder() .url("") .post(body) .build(); Call call = client.newCall(request); call.enqueue(new Callback() {//异步请求 @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { } }); 复制代码
new RequestBody(); RequestBody.create(byte[]); RequestBody.create(File, MediaType); //上传文件是用到 RequestBody.create(byte[], MediaType); //上传二进制字节时用到 RequestBody.create(String, MediaType); //上传文本时用到 RequestBody.create(ByteString, MediaType); //上传字节流时用到 RequestBody.create(byte[], MediaType,int offset); // offset 从offset开始上传 RequestBody.create(byte[], MediaType,int offset,int byteCount ); // offset, byteCount 从offset开始,到offset后byteCount字节结束,上传 new MultipartBody(); new MultipartBody.Builder(); builder.setType(MediaType); //MultipartBody.FORM 设置类型是表单 builder.addFormDataPart(String, String); //添加数据 builder.addFormDataPart(String, String, RequestBody); //添加上传的文件及必要信息 builder.build(); //返回RequestBody new MediaType(); MediaType.parse(String); //设置上传的文件的类型 复制代码
对网络请求RequestBody进行来代理
这里直接上代码
activity_main 同上
MainActivity
public class MainActivity extends AppCompatActivity { private ProgressBar progressBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); PermissionUtil.getPermissions(this, PermissionUtil.READ_EXTERNAL_STORAGE, PermissionUtil.WRITE_EXTERNAL_STORAGE); progressBar = findViewById(R.id.progressBar); findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { upload(); } }); } public void upload() { Map<String, String> map = new HashMap<>(); String path = Environment.getExternalStorageDirectory().getPath() + "/Download/123.jpg"; File file = new File(path); String url = ""; OkHttpHelper.getInstance().setUploadUrl(url).startUpload(map, file, new OkHttpHelper.UploadCallback() { @Override public void start(long max) { } @Override public void loading(long progress) { } @Override public void complete(String msg) { } @Override public void fail(String message) { } }); } } 复制代码
OkHttpHelper
public class OkHttpHelper { private static OkHttpHelper instance = null; private OkHttpClient client; private Request request; private OkHttpHelper() { initOkHttp();//初始化 } static OkHttpHelper getInstance() {//单例模式 if (instance == null) { synchronized (OkHttpHelper.class) { if (instance == null) { instance = new OkHttpHelper(); } } } return instance; } public OkHttpHelper setUploadUrl(String url) { request = new Request.Builder() .url(url) .build(); return this; } public void startUpload(Map<String, String> map, File file,final UploadCallback callback) { //重构Request,在.post()中传入的请求体 Request request = this.request.newBuilder().post(new MyRequestBody(setUploadBody(map, file),callback)).build(); Call call = client.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { callback.fail(e.getMessage()); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { callback.complete(response.body().string()); } }); } private static class MyRequestBody extends RequestBody { RequestBody body = null; UploadCallback callback; public MyRequestBody(MultipartBody multipartBody, UploadCallback callback) { super(); body = multipartBody; this.callback = callback; } @Nullable @Override public MediaType contentType() { return body.contentType(); } @Override public long contentLength() throws IOException { callback.start(body.contentLength()); return body.contentLength(); } @Override public void writeTo(@NotNull BufferedSink bufferedSink) throws IOException { //包装 Sink sk = sink(bufferedSink); bufferedSink = Okio.buffer(sk); //写入 body.writeTo(bufferedSink); //必须调用flush,否则最后一部分数据可能不会被写入 bufferedSink.flush(); } /** * 写入,回调进度接口 * * @param sink Sink * @return Sink */ private Sink sink(Sink sink) { return new ForwardingSink(sink) { long bytesWritten = 0L; @Override public void write(Buffer source, long byteCount) throws IOException { super.write(source, byteCount); //获取上传进度 bytesWritten += byteCount; callback.loading(bytesWritten); } }; } } //将需要上传的数据进行打包 private MultipartBody setUploadBody(Map<String, String> map, File file) { MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM); RequestBody fileBody = RequestBody.create(file, MediaType.parse("image/png")); if (map != null && map.size() > 0) { for (String key : map.keySet()) { String value = map.get(key); if (value != null) { builder.addFormDataPart(key, value); } } } return builder.addFormDataPart("file", "fileName", fileBody).build(); } public interface UploadCallback { //开始上传 void start(long max);//传入文件总字节数 //正在上传 void loading(long progress);//传入已下载的字节数 //上传完成 void complete(String msg); //请求失败 void fail(String message); } } 复制代码
拦截器是一种强大的机制,可以监视、重写和重试调用。
//这是一个最简单的拦截器 static class MyInterceptor implements Interceptor { @NotNull @Override public Response intercept(@NotNull Chain chain) throws IOException { Request request = chain.request(); Response response = chain.proceed(request); return response; //return chain.proceed(chain.request()); } } //如何使用 OkHttpHelper client = new OkHttpClient.Builder() .addInterceptor(new MyInterceptor()) //注册应用拦截器 .addNetworkInterceptor()//注册网络拦截器 .build(); 复制代码
调用chain.proceed(request)是每个拦截器实现的关键部分。这种简单的方法是所有HTTP工作发生的地方,它会产生一个响应来满足请求。如果chain.proceed(request)被多次调用,则必须关闭先前的响应主体。(官方翻译)
应用拦截器 无需担心中间响应,例如重定向和重试。 即使从缓存提供HTTP响应,也总是被调用一次。 遵守应用程序的原始意图。不关心OkHttp注入的标头,例如If-None-Match。 允许短路而不是Chain.proceed()。 允许重试并多次致电Chain.proceed()。
网络拦截器 能够对重定向和重试之类的中间响应进行操作。 不会为使网络短路的缓存响应调用。 观察数据,就像通过网络传输数据一样。 访问Connection带有请求的。
重写请求 重写响应
重试及重定向拦截器 RetryAndFollowUpInterceptor 桥接拦截器 BridgeInterceptor 缓存拦截器 CacheInterceptor 连接拦截器 ConnectInterceptor 读写拦截器 CallServerInterceptor
日志打印 LoggerInterceptor 打印网络请求的头信息 打印请求的网址 缓存:cache-control, max-age=xxx
new Cache(File,long,FileSystem); //设置缓存数使用,long有效缓存时长 new Cache(File,long); //设置缓存数使用 new OkHttpClient(); newBuilder();自定义一个共享的OkHttpClient实例 new OkHttpClient.Builder() builder.connectTimeout(Long, TimeUnit); //long 设置连接超时时长,TimeUnit 设置时间单位(时,分,秒) builder.readTimeout(Long, TimeUnit); //long 设置读取超时时长, builder.writeTimeout(Long, TimeUnit); //long 设置写入超时时长, builder.addInterceptor(Interceptor); //设置拦截器 builder.cache(Cache); //设置缓存 builder.build(); //返回 OkHttpClient new MediaType(); MediaType.parse(String); new RequestBody(); RequestBody.create(byte[]); RequestBody.create(File, MediaType); //上传文件是用到 RequestBody.create(byte[], MediaType); //上传二进制字节时用到 RequestBody.create(String, MediaType); //上传文本时用到 RequestBody.create(ByteString, MediaType); //上传字节流时用到 RequestBody.create(byte[], MediaType,int offset); // offset 从offset开始上传 RequestBody.create(byte[], MediaType,int offset,int byteCount); // offset, byteCount 从offset开始,到offset后byteCount字节结束,上传 new FormBody(); //设置表单 new FormBody.Builder(); formBody.add(String, String); formBody.build(); //返回RequestBody new MultipartBody(); new MultipartBody.Builder(); builder.setType(MediaType); //MultipartBody.FORM 设置类型是表单 builder.addFormDataPart(String, String); //添加数据 builder.addFormDataPart(String, String, RequestBody); builder.build(); //返回RequestBody new Request(); new Request.Builder(); builder.url(String); builder.post(RequestBody); builder.addHeader(String, String); //设置请求头 builder.method(String, RequestBody) //设置请求类型(GET,POST)和请求体 builder.build(); new Call(); call.execute(); //同步请求 call.enqueue(Callback); //异步请求 call.cancel(); //请求终止 new Response(); response.body(); response.body().string(); response.body().bytes(); response.body().byteStream();复制代码