Android网络请求库的使用(okhttp、retrofit、rxjava)

本文详细介绍了如何在Android项目中使用OkHttp进行GET/POST请求,包括同步和异步写法,以及如何配合Retrofit和RxJava进行类型安全的API调用。通过实例演示了参数拼接、拦截器和复杂请求流程的处理。
摘要由CSDN通过智能技术生成

前置工作

首先新建项目,添加网络权限,这个权限不需要⽤户授权, 默认申请就给, 不添加的话会报错:
在这里插入图片描述
然后在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();
    }

需要注意的点:

  1. 由于网络请求不能放在主线程中,所以我们新开一个线程去发送网络请求
  2. 由于更新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请求案例,综合应用

主要逻辑:

  1. 获取⽤户列表
  2. 显示⽤户列表⽤户总个数
  3. 创建新⽤户
  4. 显示创建的⽤户的名字
  5. 登录
  6. 显示登录的token
  7. 获取单个⽤户信息
  8. 显示⽤户的头像

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() {
                    }
                })
        ;
    }
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值