OkHttp&Retrofit
OkHttp的使用
-
导入依赖
implementation("com.squareup.okhttp3:okhttp:4.9.0")
-
使用
-
Get
-
同步请求:注意在Android开发中同步请求会等待请求执行完毕,再往下走,同时,同步网络请求需要在子线程中使用,同步调用的execute方法。
new Thread(()->{ Request request = new Request.Builder().url("https://www.httpbin.org/get?key=1&value=2").build(); //准备请求的Call对象 Call call = mOkHttpClient.newCall(request); try { Response response = call.execute(); Log.d(TAG, "getSync: response = "+response.body().string()); } catch (IOException e) { e.printStackTrace(); } }).start();
-
异步请求,异步调用的是enqueue方法,同时这里要注意onResponse不一定是成功的需要判断状态码为200-300之间,这里用isSuccessful判断即可
Request request = new Request.Builder().url("https://www.httpbin.org/get?key=1&value=2").build(); //准备请求的Call对象 Call call = mOkHttpClient.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(@NonNull Call call, @NonNull IOException e) { } @Override public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { if (response.isSuccessful()){ Log.d(TAG, "onResponse: success:"+response.body().string()); } } });
-
-
Post
-
同步请求,Request.Builder默认是GET,这里需要调用Post,同时需要一个RequestBody参数,这里使用的是Form表单的格式
new Thread(()->{ FormBody formBody = new FormBody.Builder() .add("key", "1") .add("value", "2").build(); Request request = new Request.Builder() .url("https://www.httpbin.org/post") .post(formBody) .build(); Call call = mOkHttpClient.newCall(request); try { Response response = call.execute(); Log.d(TAG, "postSync: response = " + response.body().string()); } catch (IOException e) { e.printStackTrace(); } }).start();
-
异步请求
FormBody formBody = new FormBody.Builder() .add("key", "1") .add("value", "2").build(); Request request = new Request.Builder() .url("https://www.httpbin.org/post") .post(formBody) .build(); //准备请求的Call对象 Call call = mOkHttpClient.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(@NonNull Call call, @NonNull IOException e) { } @Override public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { if (response.isSuccessful()){ Log.d(TAG, "onResponse: success:"+response.body().string()); } } }); }
-
-
-
OKHttp上传文件,MediaType.parse根据上传文件类型进行修改,TXT格式的类型就是text/plain
public void uploadFile() throws IOException { OkHttpClient okHttpClient = new OkHttpClient(); File file = new File(filePath); File file2 = new File(filePath); MultipartBody multipartBody = new MultipartBody.Builder() .addFormDataPart("file1", file.getName(), RequestBody.create(file, MediaType.parse("text/plain"))) .addFormDataPart("file2", file2.getName(), RequestBody.create(file2, MediaType.parse("text/plain"))) .build(); Request request = new Request.Builder().url("https://www.httpbin.org/post") .post(multipartBody) .build(); Call call = okHttpClient.newCall(request); Response response = call.execute(); System.out.println(response.body().string()); }
-
发送Json请求
public void jsonTest() throws IOException { OkHttpClient okHttpClient = new OkHttpClient(); RequestBody requestBody = RequestBody.create("{\"key\":1,\"value\":2}", MediaType.parse("application/json\n")); Request request = new Request.Builder().url("https://www.httpbin.org/post") .post(requestBody) .build(); Call call = okHttpClient.newCall(request); Response response = call.execute(); System.out.println(response.body().string()); }
-
拦截器、缓存:创建OKHttpClient的时候采用构建者模式进行创建,.addInterceptor添加拦截器,在intercept方法中可以进行Request请求的处理,这里只是添加了请求头;.addNetWorkInterceptor同样也是拦截器不过它是在addInterceptor后执行;开启缓存,默认是关闭的,通过.cache开启new一个Cache传入要缓存进的文件地址以及缓存大小即可
public void interceptorTest() throws IOException { OkHttpClient okHttpClient = new OkHttpClient.Builder() .cache(new Cache(new File("/path/cache"),1024*1024)) .addInterceptor(new Interceptor() { @NonNull @Override public Response intercept(@NonNull Chain chain) throws IOException { Request request = chain.request().newBuilder() .addHeader("os", "android") .addHeader("version", "1.0") .build(); Response response = chain.proceed(request); return response; } }) .addNetworkInterceptor(new Interceptor() { @NonNull @Override public Response intercept(@NonNull Chain chain) throws IOException { System.out.println("version:" + chain.request().header("version")); return chain.proceed(chain.request()); } }).build(); Request request = new Request.Builder().url("https://www.httpbin.org/get?key=1&value=2").build(); Call call = okHttpClient.newCall(request); Response response = call.execute(); System.out.println(response.body().string()); }
-
Cookie:这里使用了wanAndroid中的开源请求方法,需要注册使用
List<Cookie> cookies = new ArrayList<>(); @Test public void cookieTest() throws IOException { OkHttpClient okHttpClient = new OkHttpClient.Builder() .cookieJar(new CookieJar() { @Override public void saveFromResponse(@NonNull HttpUrl httpUrl, @NonNull List<Cookie> list) { cookies = list; } @NonNull @Override public List<Cookie> loadForRequest(@NonNull HttpUrl httpUrl) { if (httpUrl.host().equals("www.wanandroid.com")){ return cookies; } return null; } }) .build(); FormBody formBody = new FormBody.Builder().add("username", "") .add("password", "") .build(); Request request = new Request.Builder().url("https://www.wanandroid.com/user/login") .post(formBody) .build(); Call call = okHttpClient.newCall(request); Response response = call.execute(); System.out.println(response.body().string()); request = new Request.Builder().url("https://www.wanandroid.com/lg/collect/list/0/json") .build(); call = okHttpClient.newCall(request); response = call.execute(); System.out.println(response.body().string()); }
Retrofit
入门使用
-
创建Http接口,注意这里如果是GET请求则参数的注解为Query;如果是POST请求,则根据请求类型进行参数注解的添加,这里的请求体类型为FromUrlEncoded,所以请求参数为Field;还有就是这里的方法名是可变的请求类型由方法上的注解决定:
public interface HttpService { @GET("get") Call<ResponseBody> get(@Query("username") String username, @Query("password") String password); @POST("post") @FormUrlEncoded Call<ResponseBody> post(@Field("username") String username, @Field("password") String password); }
-
创建Retrofit实例
private Retrofit mRetrofit = new Retrofit.Builder().baseUrl("https://www.httpbin.org/").build();
-
根据实例进行创建接口实例
HttpService httpService = mRetrofit.create(HttpService.class);
-
然后就是调用方法生成Call对象
retrofit2.Call<ResponseBody> post = httpService.post("Hello", "World");
-
最后就是进行请求
post.enqueue(new retrofit2.Callback<ResponseBody>() { @Override public void onResponse(retrofit2.Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) { if (response.isSuccessful()){ try { Log.d(TAG, "onResponse: success:"+response.body().string()); } catch (IOException e) { e.printStackTrace(); } } } @Override public void onFailure(retrofit2.Call<ResponseBody> call, Throwable t) { } });
Retrofit注解
-
Path
@POST("{id}") @FormUrlEncoded Call<ResponseBody> postPath(@Path("id")String path, @Field("username") String username, @Field("password") String password);
Retrofit mRetrofit = new Retrofit.Builder().baseUrl("https://www.httpbin.org/").build(); HttpService httpService = mRetrofit.create(HttpService.class); @Test public void postPathTest() throws IOException { Response<ResponseBody> post = httpService .postPath("post","11","22") .execute(); System.out.println(post.body().string()); }
-
Headers
@Headers({"os:android","version:1.0"}) @POST("post") Call<ResponseBody> postHeaders();
@Test public void postHeadersTest() throws IOException { Response<ResponseBody> post = httpService .postHeaders() .execute(); System.out.println(post.body().string()); }
-
Url
@POST Call<ResponseBody> postUrl(@Url String url);
@Test public void postUrlTest() throws IOException { Response<ResponseBody> post = httpService .postUrl("https://www.httpbin.org/post") .execute(); System.out.println(post.body().string()); }
-
QueryMap
@GET("get") Call<ResponseBody> getMap(@QueryMap Map<String,String> map);
public void getAsync(View view) { HttpService httpService = mRetrofit.create(HttpService.class); HashMap<String,String> hashMap = new HashMap<>(); hashMap.put("username","1111"); hashMap.put("password","2222"); retrofit2.Call<ResponseBody> call = httpService.getMap(hashMap); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(retrofit2.Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) { if (response.isSuccessful()){ try { Log.d(TAG, "onResponse: success:"+response.body().string()); } catch (IOException e) { e.printStackTrace(); } } } @Override public void onFailure(retrofit2.Call<ResponseBody> call, Throwable t) { } }); }
-
Header
@POST("{id}") @FormUrlEncoded Call<ResponseBody> postHeader(@Path("id")String path, @Header("os")String os, @Field("username") String username, @Field("password") String password);
@Test public void postHeaderTest() throws IOException { Response<ResponseBody> post = httpService .postHeader("post","android","11","22") .execute(); System.out.println(post.body().string()); }
Retrofit转换器
转化器就是对我们获取到responseBody进行转换,之前我们只能拿到String或者byte等类型,但我们使用转换器之后又就可以转换成我们需要使用的JavaBean等;这里我推荐一个在线Json转JavaBean的工具网站:https://www.bejson.com/json2javapojo/new/
Retrofit mRetrofit = new Retrofit.Builder().baseUrl("https://www.wanandroid.com/").build();
WanAndroidService mWanAndroidService = mRetrofit.create(WanAndroidService.class);
-
引入依赖
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
这里我们也可以引入Gson的依赖来进行转换,但使用起来并没有Retrofit的converter-gson好用
-
使用
-
使用Gson
@POST("user/login") @FormUrlEncoded Call<ResponseBody> postLogin(@Field("username")String username, @Field("password") String password);
注意,这里的Call里面的泛型为ResponseBody
@Test public void postLoginTest() throws IOException { Response<ResponseBody> post = mWanAndroidService .postLogin("", "") .execute(); Gson gson = new Gson(); if (post.body() != null) { BaseResponse baseResponse = gson.fromJson(post.body().string(), BaseResponse.class); System.out.println(baseResponse); } else { System.out.println("Post body is null"); } }
-
使用converter-gson
@POST("user/login") @FormUrlEncoded Call<BaseResponse> loginConverter(@Field("username")String username, @Field("password") String password);
这里我们使用的泛型为实体类
@Test public void postLoginConverterTest() throws IOException { Retrofit converterRetrofit = new Retrofit.Builder() .baseUrl("https://www.wanandroid.com/") .addConverterFactory(GsonConverterFactory.create()) //添加转换器 .build(); WanAndroidService wanAndroidService = converterRetrofit.create(WanAndroidService.class); Response<BaseResponse> post = wanAndroidService .loginConverter("", "") .execute(); BaseResponse baseResponse = post.body(); System.out.println(baseResponse); }
-
使用RxJava3转换器
-
引入依赖
implementation 'com.squareup.retrofit2:adapter-rxjava3:latest.version'
如果我们引入上面的3.0及以后的版本我们是无法使用转换器的,我们可以使用下面的,通常我们也会引入RxAndroid使用
implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0' implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
-
使用
@POST("user/login") @FormUrlEncoded Flowable<BaseResponse> getLogin(@Field("username")String username, @Field("password") String password); @GET("lg/collect/list/{pageNum}/json") Flowable<ResponseBody> getArticle(@Path("pageNum")int pageNum);
这里我们通过登录然后再进行获取收藏列表
//Android主线程:AndroidSchedulers.mainThread(); //单元测试中无法使用Android主线程 List<Cookie> cookies = new ArrayList<>(); @Test public void postLoginRxJavaTest() throws IOException { //这里如果需要使用Cookie来获取登录结果,但Cookie需要OKHttpClient对象,这里可以使用 //CallFactory来进行创建 Retrofit rxJavaRetrofit = new Retrofit.Builder() .baseUrl("https://www.wanandroid.com/") .callFactory(new OkHttpClient .Builder() .cookieJar(new CookieJar() { @Override public void saveFromResponse(@NonNull HttpUrl httpUrl, @NonNull List<Cookie> list) { cookies = list; } @NonNull @Override public List<Cookie> loadForRequest(@NonNull HttpUrl httpUrl) { if (httpUrl.host().equals("www.wanandroid.com")){ return cookies; } return null; } }).build()) .addConverterFactory(GsonConverterFactory.create()) //添加转换器 .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) //添加Rxjava3的适配器 .build(); WanAndroidService wanAndroidService = rxJavaRetrofit.create(WanAndroidService.class); wanAndroidService .getLogin("", "") .flatMap(new Function<BaseResponse, Publisher<ResponseBody>>() { //flatMap:根据apply的结果生成一个新的Publisher @Override public Publisher<ResponseBody> apply(BaseResponse baseResponse) throws Throwable { //return null; return wanAndroidService.getArticle(0); } }) .observeOn(Schedulers.io()) .subscribeOn(Schedulers.newThread()) //这里我们可以切换Android主线程进行下面的UI操作,但在单元测试中我们无法使用所以就创建一个新线程了 .subscribe(new Consumer<ResponseBody>() { @Override public void accept(ResponseBody responseBody) throws Throwable { //如果实在Android中,此处可以进行UI操作 System.out.println(responseBody.string()); } }); //这里使用阻塞来获取返回值,否则就直接结束了 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } }
Rxtrofit文件上传下载
上代码:
@POST("post")
@Multipart
Call<ResponseBody> uploadFile(@Part MultipartBody.Part file);
//如果文件过大则可以加@Streaming注解,可以有效避免出现内存溢出的问题
@Streaming
@GET
Flowable<ResponseBody> downloadFile(@Url String url);
上传:
@Test
public void uploadFileWithRetrofit() throws IOException {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://www.httpbin.org")
.build();
HttpService httpService = retrofit.create(HttpService.class);
File file = new File("");
MultipartBody.Part part = MultipartBody.Part
.createFormData("file",
file.getName(),
RequestBody.create(file, MediaType.parse("text/plain")));
retrofit2.Call<ResponseBody> uploadFile = httpService.uploadFile(part);
System.out.println(uploadFile.execute().body().string());
}
下载:
@Test
public void downloadFile() throws InterruptedException {
Retrofit retrofit = new Retrofit.Builder()
.addCallAdapterFactory(RxJava3CallAdapterFactory.create())
.baseUrl("https://www.httpbin.org")
.build();
HttpService httpService = retrofit.create(HttpService.class);
httpService
.downloadFile("url地址")
.map(new Function<ResponseBody, File>() {
@Override
public File apply(ResponseBody responseBody) throws Throwable {
File file = new File("");
InputStream inputStream = responseBody.byteStream();
FileOutputStream outputStream = new FileOutputStream(file);
int length;
byte[] buffer = new byte[1024];
while ((length = inputStream.read(buffer)) != -1){
outputStream.write(buffer,0,length);
}
outputStream.close();
inputStream.close();
return file;
}
}).observeOn(Schedulers.io())
.subscribeOn(Schedulers.newThread())
.subscribe(new Consumer<File>() {
@Override
public void accept(File file) throws Throwable {
//do something...
}
});
Thread.sleep(1000);
}