Android网络请求库的使用
前置工作
首先新建项目,添加网络权限,这个权限不需要⽤户授权, 默认申请就给, 不添加的话会报错:
然后在gradle中添加一下依赖:
dependencies {
implementation 'com.squareup.okhttp3:okhttp:4.9.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
implementation 'io.reactivex.rxjava2:rxjava:2.2.20'
}
okhttp的基本使用
MainActivity.java文件大致如下:
package com.example.okhttpuse;
//导入的包,此处略
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "okhttpuse";
private final OkHttpClient client = new OkHttpClient();
private TextView tvContent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn_test).setOnClickListener(this);
tvContent = findViewById(R.id.tv_content);
}
@Override
public void onClick(View v) {
okhttpPostDemo(); //此处填入要测试的方法
}
void okhttpDemo(){
//见下文
}
void okhttpAsyncDemo(){ //相比于同步的写法,这样的写法无需我们自己再写一个Thread,okhttp会帮我们把请求放到异步中去执行
//见下文
}
void okhttpParams(){ //对于get请求 拼接请求参数
//见下文
}
void okhttpPostDemo(){
//见下文
}
}
okhttp第一个demo
void okhttpDemo(){
Request request = new Request.Builder().url("https://reqres.in/api/users?page=2").build();
tvContent.setText("请求中......");
new Thread(new Runnable() {
@Override
public void run() {
try {
Response response = client.newCall(request).execute();
Log.d(TAG,"okhttpdemo:" + response.body().string());
runOnUiThread(new Runnable() { //更新UI不能在⼦线程当中, 必须在主线程当中或UI线程当中
@Override
public void run() {
tvContent.setText("请求返回的状态码为:" + response.code());
}
});
} catch (Exception e){
e.printStackTrace();
}
}
}).start();
}
需要注意的点:
- 由于网络请求不能放在主线程中,所以我们新开一个线程去发送网络请求
- 由于更新UI不能放在子线程当中,只能在主线程中或UI线程中,所以我们把更新UI卸载UI线程中
okhttp的异步写法,更常见
void okhttpAsyncDemo(){ //相比于同步的写法,这样的写法无需我们自己再写一个Thread,okhttp会帮我们把请求放到异步中去执行
Request request = new Request.Builder().url("https://reqres.in/api/users?page=2").build();
tvContent.setText("请求中......");
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) { //请求失败的情况下走这个回调
Log.d(TAG, "onFailure:请求失败");
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { //请求成功的情况下走这个回调
Log.d(TAG, "onResponse:" + response.body().string());
runOnUiThread(new Runnable() { //更新UI不能在⼦线程当中
@Override
public void run() {
tvContent.setText("请求返回的状态码为:" + response.code());
}
});
}
});
}
GET请求中使用okhttp拼接参数
void okhttpParams(){ //对于get请求 拼接请求参数
HttpUrl.Builder builder = HttpUrl.parse("https://reqres.in/api/users").newBuilder();
builder.addQueryParameter("page","2");
String url = builder.build().toString();
Log.d(TAG, "okhttpParams: " + url);
}
okhttp发起POST请求
void okhttpPostDemo(){
RequestBody body = new FormBody.Builder()
.add("name","yuanrenxue")
.add("job","developer")
.build();
Request request = new Request.Builder().url("https://reqres.in/api/users")
.post(body).build();
tvContent.setText("请求中......");
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
Log.d(TAG, "onFailure:请求失败");
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
Log.d(TAG, "onResponse:" + response.body().string());
runOnUiThread(new Runnable() { //更新UI不能在⼦线程当中, 必须在主线程当中
@Override
public void run() {
tvContent.setText("请求返回的状态码为:" + response.code());
}
});
}
});
}
拦截器第一个demo,打印请求的时间
首先新建一个类:LoggingInterceptor
package com.example.okhttpuse;
//导包略过
public class LoggingInterceptor implements Interceptor {
private static final String TAG = "yuanrenxue";
@NotNull
@Override
public Response intercept(@NotNull Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
Response response = chain.proceed(request);
long t2 = System.nanoTime();
Log.d(TAG, "intercept: " + (t2 - t1));
return response;
}
}
测试结果:
retrofit的基本使用
retrofit:对okhttp3进⾏了⼀个封装, 是⼀个类型安全的http客户端,我们可以指定请求参数的类型,也可以指定返回值的类型,对于返回值我们可以直接解析成一个java对象。
retrofit第一个demo:GET请求
主要用法:
新建一个Interface:
public interface ApiService {
@GET("api/users") //具体请求的URL以及请求方式:GET请求
Call<PageResponseBean> listUsers(@Query("page") Integer page); //<PageResponseBean>:直接把返回的数据json序列化成为java中的对象
//listUsers:具体请求的名字 //(@Query("page") Integer page):具体请求的参数,参数为page,类型为Integer
}
再新建一个PageResponseBean类:
public class PageResponseBean {
@SerializedName("page") //需要把哪一个字段进行序列化,对应json中的key
Integer page;
@SerializedName("total_pages")
Integer totalPages;
}
主要方法如下:
void retrofitGetDemo(){
tvContent.setText("请求中...");
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://reqres.in")
.addConverterFactory(GsonConverterFactory.create()) //把服务端返回的json字符串转化成java中的对象
.build();
retrofit.create(ApiService.class).listUsers(2).enqueue(new retrofit2.Callback<PageResponseBean>() {
@Override
public void onResponse(retrofit2.Call<PageResponseBean> call, retrofit2.Response<PageResponseBean> response) {
Log.d(TAG, "onResponse: " + response.body().page);
tvContent.setText("请求的状态码为:" + response.code());
}
@Override
public void onFailure(retrofit2.Call<PageResponseBean> call, Throwable t) {
}
});
}
和普通的okhttp相比,retrofit对okhttp进行了封装,这里并没有显式地去调用url,免去了我们手动切换ui线程。
retrofit发送post请求
对ApiService进行修改:
public interface ApiService {
@GET("api/users") //具体请求的URL以及请求方式:GET请求
Call<PageResponseBean> listUsers(@Query("page") Integer page); //<PageResponseBean>:直接把返回的数据json序列化成为java中的对象
//listUsers:具体请求的名字 //(@Query("page") Integer page):具体请求的参数,参数为page,类型为Integer
@POST("api/users")
@FormUrlEncoded //进行url编码,直接写的话可能会出现问题
Call<UserBean> createUser(@Field("name") String name,@Field("job") String job );
}
新建一个UserBean类:
public class UserBean {
@SerializedName("name")
String name;
}
主要方法如下:
void retrofitPostDemo(){
tvContent.setText("请求中...");
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://reqres.in")
.addConverterFactory(GsonConverterFactory.create()) //把服务端返回的json字符串转化成java中的对象
.build();
retrofit.create(ApiService.class).createUser("yuanrenxue","developer").enqueue(new retrofit2.Callback<UserBean>() {
@Override
public void onResponse(retrofit2.Call<UserBean> call, retrofit2.Response<UserBean> response) {
Log.d(TAG, "onResponse: " + response.body().name);
tvContent.setText("请求的状态码为:" + response.code());
}
@Override
public void onFailure(retrofit2.Call<UserBean> call, Throwable t) {
}
});
}
测试结果:
rxjava的基本使用
rxjava:响应式编程的库, 结合retrofit的使⽤。
第一个demo:GET请求
对ApiService进行修改:
@GET("api/users")
Observable<PageResponseBean> rxlistUsers(@Query("page") Integer page);
主要方法如下:
void rxJavaGetDemo(){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://reqres.in")
.addConverterFactory(GsonConverterFactory.create()) //把服务端返回的json字符串转化成java中的对象
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
retrofit.create(ApiService.class).rxlistUsers(2)
.subscribeOn(Schedulers.io()) //把具体请求放到子线程中(异步线程)
.observeOn(AndroidSchedulers.mainThread()) //将下面的subscribe的东西放到UI线程
.subscribe(new Observer<PageResponseBean>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
tvContent.setText("请求中...");
}
@Override
public void onNext(@NonNull PageResponseBean pageResponseBean) {
Log.d(TAG, "onNext: " + pageResponseBean.totalPages); //打印总的页数
}
@Override
public void onError(@NonNull Throwable e) {
e.printStackTrace();
}
@Override
public void onComplete() {
tvContent.setText("请求完成!");
}
});
}
发送POST请求
对ApiService进行修改:
@POST("api/users")
@FormUrlEncoded //进行url编码,直接写的话可能会出现问题
Observable<UserBean> rxCreateUser(@Field("name") String name,@Field("job") String job );
主要方法如下:
void rxJavaPostDemo(){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://reqres.in")
.addConverterFactory(GsonConverterFactory.create()) //把服务端返回的json字符串转化成java中的对象
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
retrofit.create(ApiService.class).rxCreateUser("yuanrenxue","developer")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<UserBean>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
tvContent.setText("请求中...");
}
@Override
public void onNext(@NonNull UserBean userBean) {
tvContent.setText("用户创建成功:" + userBean.name);
}
@Override
public void onError(@NonNull Throwable e) {
e.printStackTrace();
}
@Override
public void onComplete() {
//tvContent.setText("请求完成!");
}
});
}
一个较为复杂的Android请求案例,综合应用
主要逻辑:
- 获取⽤户列表
- 显示⽤户列表⽤户总个数
- 创建新⽤户
- 显示创建的⽤户的名字
- 登录
- 显示登录的token
- 获取单个⽤户信息
- 显示⽤户的头像
PageResponseBean:
public class PageResponseBean {
@SerializedName("page") //需要把哪一个字段进行序列化,对应json中的key
Integer page;
@SerializedName("total_pages")
Integer totalPages;
@SerializedName("total")
Integer total;
}
UserBean:
public class UserBean {
@SerializedName("name")
String name;
@SerializedName("avatar")
String avatar;
}
新建一个UserDetailBean类:
public class UserDetailBean {
@SerializedName("data")
UserBean data;
}
新建一个LoginBean类:
public class LoginBean {
@SerializedName("token")
String token;
}
ApiService:
public interface ApiService {
@GET("api/users") //具体请求的URL以及请求方式:GET请求
Call<PageResponseBean> listUsers(@Query("page") Integer page); //<PageResponseBean>:直接把返回的数据json序列化成为java中的对象
//listUsers:具体请求的名字 //(@Query("page") Integer page):具体请求的参数,参数为page,类型为Integer
@POST("api/users")
@FormUrlEncoded //进行url编码,直接写的话可能会出现问题
Call<UserBean> createUser(@Field("name") String name,@Field("job") String job );
@GET("api/users")
Observable<PageResponseBean> rxlistUsers(@Query("page") Integer page);
@POST("api/users")
@FormUrlEncoded //进行url编码,直接写的话可能会出现问题
Observable<UserBean> rxCreateUser(@Field("name") String name,@Field("job") String job );
@POST("api/users")
@FormUrlEncoded
Observable<LoginBean> login(@Field("email") String email,@Field("password") String password);
@GET("api/users/{userId}") //只有路径参数
Observable<UserDetailBean> rxUserInfo(@Path("userId") Integer userId);
//图片请求的url,如https://reqres.in/img/faces/2-image.jpg
@GET("img/faces/{path}")
Observable<ResponseBody> getAvatar(@Path("path") String path);
}
以下是主要代码:
void finalDemo(){
//首先创建一个retrofit对象
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://reqres.in")
.addConverterFactory(GsonConverterFactory.create()) //把服务端返回的json字符串转化成java中的对象
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
//获取用户列表
retrofit.create(ApiService.class).rxlistUsers(2)
.subscribeOn(Schedulers.io()) //把网络请求切换到异步线程
.observeOn(AndroidSchedulers.mainThread()) //把对界面的修改内容,也就是请求返回的内容,切换到主线程
.doOnNext(new Consumer<PageResponseBean>() {
@Override
public void accept(PageResponseBean pageResponseBean) throws Exception {
tvContent.setText("总人数为:" + pageResponseBean.total); // 显示用户列表总个数:total
}
})
.observeOn(Schedulers.io()) //再次切换到异步线程
.flatMap(new Function<PageResponseBean, ObservableSource<UserBean>>() {
@Override
public ObservableSource<UserBean> apply(@NonNull PageResponseBean pageResponseBean) throws Exception {
return retrofit.create(ApiService.class).rxCreateUser("yuanrenxue","developer");
}
}) //创建一个新的用户
.observeOn(AndroidSchedulers.mainThread()) //切换回主线程
.doOnNext(new Consumer<UserBean>() {
@Override
public void accept(UserBean userBean) throws Exception {
tvContent.setText("当前用户名字:" + UserBean.class);
}
}) //显示当前的用户名
.observeOn(Schedulers.io())
.flatMap(new Function<UserBean, ObservableSource<LoginBean>>() {
@Override
public ObservableSource<LoginBean> apply(@NonNull UserBean userBean) throws Exception {
return retrofit.create(ApiService.class).login("hhhh@163.com","asd12356");
}
})
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(new Consumer<LoginBean>() {
@Override
public void accept(LoginBean loginBean) throws Exception {
tvContent.setText("当前的用户token是:" + loginBean.token);
}
}) //登录获取用户token并且显示出来
.observeOn(Schedulers.io())
.flatMap(new Function<LoginBean, ObservableSource<UserDetailBean>>() {
@Override
public ObservableSource<UserDetailBean> apply(@NonNull LoginBean loginBean) throws Exception {
return retrofit.create(ApiService.class).rxUserInfo(2);
}
})
.observeOn(AndroidSchedulers.mainThread())
.flatMap(new Function<UserDetailBean, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(@NonNull UserDetailBean userDetailBean) throws Exception {
return Observable.just(userDetailBean.data.avatar);
}
}) //返回用户头像的地址
.observeOn(Schedulers.io())
.flatMap(new Function<String, ObservableSource<ResponseBody>>() {
@Override
public ObservableSource<ResponseBody> apply(@NonNull String s) throws Exception {
String[] paths = s.split("/");
String path = paths[paths.length-1];
return retrofit.create(ApiService.class).getAvatar(path);
}
})
.map(new Function<ResponseBody, Bitmap>() {
@Override
public Bitmap apply(@NonNull ResponseBody responseBody) throws Exception {
return BitmapFactory.decodeStream(responseBody.byteStream());
}
}) //获取用户头像,转换成为Bitmap
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Bitmap>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
tvContent.setText("请求中...");
}
@Override
public void onNext(@NonNull Bitmap bitmap) {
ivAvatar.setImageBitmap(bitmap);
}
@Override
public void onError(@NonNull Throwable e) {
}
@Override
public void onComplete() {
}
})
;
}