OKHttp&Retrofit

本文详细介绍了如何在Android中使用OKHttp进行HTTP请求,包括GET、POST同步和异步请求,文件上传,JSON请求,拦截器和缓存的使用。接着,文章讲解了Retrofit的基本使用,如创建接口、注解方式发送请求,并展示了如何添加转换器和使用RxJava进行响应订阅。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

OkHttp&Retrofit

OkHttp的使用

  1. 导入依赖

        implementation("com.squareup.okhttp3:okhttp:4.9.0")
    
  2. 使用

    1. Get

      1. 同步请求:注意在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();
        
      2. 异步请求,异步调用的是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());
                        }
                    }
                });
        
    2. Post

      1. 同步请求,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();
        
      2. 异步请求

        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());
                        }
                    }
                });
            }
        
  3. 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());
        }
    
  4. 发送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());
        }
    
  5. 拦截器、缓存:创建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());
        }
    
  6. 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

入门使用

  1. 创建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);
    }
    
  2. 创建Retrofit实例

    private Retrofit  mRetrofit = new Retrofit.Builder().baseUrl("https://www.httpbin.org/").build();
    
  3. 根据实例进行创建接口实例

    HttpService httpService = mRetrofit.create(HttpService.class);
    
  4. 然后就是调用方法生成Call对象

    retrofit2.Call<ResponseBody> post = httpService.post("Hello", "World");
    
  5. 最后就是进行请求

    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注解

  1. 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());
        }
    
  2. 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());
        }
    
  3. 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());
        }
    
  4. 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) {
    
                }
            });
        }
    
  5. 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);
  1. 引入依赖

    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    

    这里我们也可以引入Gson的依赖来进行转换,但使用起来并没有Retrofit的converter-gson好用

  2. 使用

    1. 使用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");
              }
          }
      
    2. 使用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转换器

  1. 引入依赖

    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'
    
  2. 使用

        @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);
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

立花泷える宫水三叶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值