Retrofit基本用法

Retrofit

在这里插入图片描述

1.Retrofit注解分类

1.1HTTP请求方法

GET
POST
PUT
DELETE
HEAD
PATCH
OPTIONS
HTTP

1.2标记类注解

FormUrlEncoded
Multipart
Streaming

Streaming代表响应的数据以流的形式返回,如果不使用它,则默认会把全部数据加载到内存,所以下载大文件时需要加上这个注解.

1.3参数类注解

Header
Headers
Body
Path
Field
FieldMap
Part
PartMap
Query
QueryMap

2.GET请求访问网络

2.1无参的get请求

public interface BaiduApi {
    @GET("/")
    Call<ResponseBody> getBaiduHtml();
}
Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://www.baidu.com/")
                .build();
        BaiduApi baiduApi = retrofit.create(BaiduApi.class);
        baiduApi.getBaiduHtml().enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                try {
                    if(response.isSuccessful()) {
                        Log.d("tag", response.body().string());
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                Log.d("tag","失败");
            }
        });

最开始我的Call<>里面写的是String,最后给我报了一个

com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $

错误,chatgpt里面说由Gson库抛出的,通常表示输入的JSON数据格式不正确,

给出的解释是:

当你使用 Call<String> 时,Retrofit 需要将响应体的字节流转换为字符串,以便于你使用。但是,当响应体的内容是 HTML 时,有可能出现编码问题或者特殊字符,导致转换失败。

相比之下,使用 ResponseBody 可以让你直接操作响应体的字节流,而不需要进行转换。这样可以保证获取到原始的响应体数据,而不会因为转换失败而出现问题。

当你需要获取响应体的字节流时,或者无法确定响应体的编码格式时,建议使用 ResponseBody。而当你明确知道响应体的编码格式并且需要直接使用响应体内容时,可以考虑使用 Call<String>

所以一般还是用ResponseBody最保险

注意:baseUrl里的参数必须以 / 结尾否则会抛出异常 IllegalArgumentException

最后**Log.d(“tag”,response.body().string);**打印出来的东西为:

百度一下,你就知道

2.2动态配置URL地址@Path

public interface WithParamsBaiduApi {
    @GET("{path}")
    Call<ResponseBody>getCall(@Path("path")String path);
}
Retrofit retrofit1 = new Retrofit.Builder().baseUrl("https://so.csdn.net/so/search/")
        .build();
WithParamsBaiduApi baiduApi1 = retrofit1.create(WithParamsBaiduApi.class);
baiduApi1.getCall("?q=%E5%8A%A8%E6%80%81%E9%85%8D%E7%BD%AEURL%E5%9C%B0%E5%9D%80%40Path%20retrofit&t=&u=&urw=").enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
        if(response.isSuccessful()){
            try {
                Log.d("tag","yes"+" "+response.body().string());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
        Log.d("tag","isFail");
    }
});

baseUrl里面的url为https://so.csdn.net/so/search/但是,我的

@GET(“{path}”)

CallgetCall(@Path(“path”)String path);

表明了getCall需要参数,我的**getCall()**里面传入了

?q=%E5%8A%A8%E6%80%81%E9%85%8D%E7%BD%AEURL%E5%9C%B0%E5%9D%80%40Path%20retrofit&t=&u=&urw=

所以最后GET的为

https://so.csdn.net/so/search/?q=%E5%8A%A8%E6%80%81%E9%85%8D%E7%BD%AEURL%E5%9C%B0%E5%9D%80%40Path%20retrofit&t=&u=&urw=

最后Log.d(“tag”,response.body().string());

打印出来的为:

2.3动态指定查询条件:@Query()

public interface Query {
    @GET("ip")
    Call<ResponseBody>getbody(@retrofit2.http.Query("ip")String ip);
}
Retrofit retrofit2 = new Retrofit.Builder().baseUrl("https://so.csdn.net/so/search/").build();
Query query = retrofit2.create(Query.class);
query.getbody("q=%E5%8A%A8%E6%80%81%E9%85%8D%E7%BD%AEURL%E5%9C%B0%E5%9D%80%40Path%20retrofit&t=&u=&urw=").enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
    if(response.isSuccessful()) {
        try {
            Log.d("tag", response.body().string());
        } catch (IOException e) {
            e.printStackTrace();
            Log.d("tag","io");
        }
    }
    }

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
        Log.d("tag","失败");
    }
});

Log.d(“tag”,response.body.string());

相当于我请求:

https://so.csdn.net/so/search/ip?q=%E5%8A%A8%E6%80%81%E9%85%8D%E7%BD%AEURL%E5%9C%B0%E5%9D%80%40Path%20retrofit&t=&u=&urw=

打印出来的是:

2.4动态配置查询条件组:@QueryMap

public interface QueryMap {
@GET("ip")
Call<ResponseBody>getCall(@retrofit2.http.QueryMap Map<String,String>map);
}
 Retrofit retrofit3 = new Retrofit.Builder().baseUrl("https://so.csdn.net/so/search/").build();
        Map<String,String>map = new HashMap<>();
        map.put("q","%E5%8A%A8%E6%80%81%E9%85%8D%E7%BD%AEURL%E5%9C%B0%E5%9D%80%40Path%20retrofit&t=&u=");
        map.put("urw","");
        QueryMap queryMap = retrofit3.create(QueryMap.class);
        queryMap.getCall(map).enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                if(response.isSuccessful()){
                    try {
                        Log.d("tag",response.body().string());
                    } catch (IOException e) {
                        e.printStackTrace();
                        Log.d("tag","net");
                    }
                }
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                Log.d("tag","失败");
//                "1"
            }
        });

Log.d(“tag”,response.body().string());

相当于查询的是

https://so.csdn.net/so/search/ip?q=%E5%8A%A8%E6%80%81%E9%85%8D%E7%BD%AEURL%E5%9C%B0%E5%9D%80%40Path%20retrofit&t=&u=&urw=

出来是

3.POST请求访问网络

3.1传输数据类型为键值对: @Field

public interface postField {
    @FormUrlEncoded
    @POST("/")
    Call<WeatherBeans> requestWeatherBeans(
            @Field("app") String app,
            @Field("weaid") String weaid,
            @Field("appkey") String appkey,
            @Field("sign") String sign,
            @Field("format") String format);
}
public class WeatherBeans implements Serializable {

    @SerializedName("success")
    public String success;
    @SerializedName("result")
    public List<ResultDTO> result;

    public static WeatherBeans objectFromData(String str) {

        return new Gson().fromJson(str, WeatherBeans.class);
    }
}
public class ResultDTO implements Serializable {
    @SerializedName("weaid")
    public String weaid;
    @SerializedName("days")
    public String days;
    @SerializedName("week")
    public String week;
    @SerializedName("cityno")
    public String cityno;
    @SerializedName("citynm")
    public String citynm;
    @SerializedName("cityid")
    public String cityid;
    @SerializedName("temperature")
    public String temperature;
    @SerializedName("humidity")
    public String humidity;
    @SerializedName("weather")
    public String weather;
    @SerializedName("weather_icon")
    public String weatherIcon;
    @SerializedName("weather_icon1")
    public String weatherIcon1;
    @SerializedName("wind")
    public String wind;
    @SerializedName("winp")
    public String winp;
    @SerializedName("temp_high")
    public String tempHigh;
    @SerializedName("temp_low")
    public String tempLow;
    @SerializedName("humi_high")
    public String humiHigh;
    @SerializedName("humi_low")
    public String humiLow;
    @SerializedName("weatid")
    public String weatid;
    @SerializedName("weatid1")
    public String weatid1;
    @SerializedName("windid")
    public String windid;
    @SerializedName("winpid")
    public String winpid;
    @SerializedName("weather_iconid")
    public String weatherIconid;
    @SerializedName("weather_iconid1")
    public String weatherIconid1;

    public static ResultDTO objectFromData(String str) {

        return new Gson().fromJson(str, ResultDTO.class);
    }
}
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://api.k780.com/")
        .addConverterFactory(GsonConverterFactory.create())
        .build();
postField netService = retrofit.create(postField.class);
Call<WeatherBeans> call = netService.requestWeatherBeans("weather.future","1","10003","b59bc3ef6191eb9f747dd4e83c99f2a4","json");
call.enqueue(new Callback<WeatherBeans>() {
    @Override
    public void onResponse(Call<WeatherBeans> call, Response<WeatherBeans> response) {
        if(response.isSuccessful()){
            WeatherBeans beans = response.body();
            for (int i = 0;i<beans.result.size();i++) {
                Log.d("tag2", beans.result.get(i).cityid);
            }
        }
        Log.d("tag2",response.body().success);

    }

    @Override
    public void onFailure(Call<WeatherBeans> call, Throwable t) {
        Log.d("tag2","失败"+t);
    }
});

最后Log.d()打印出来的是:

 D/tag2: 101010100
 D/tag2: 101010100
 D/tag2: 1
3.1.1POST与GET的注解的不同
3.1.1.1GET注解

GET注解的时候,

例如这个:

public interface Query {
    @GET("ip")
    Call<ResponseBody>getbody(@retrofit2.http.Query("ip1")String ip);
}
Retrofit retrofit2 = new Retrofit.Builder().baseUrl("https://so.csdn.net/so/search/").build();
Query query = retrofit2.create(Query.class);
query.getbody("q=%E5%8A%A8%E6%80%81%E9%85%8D%E7%BD%AEURL%E5%9C%B0%E5%9D%80%40Path%20retrofit&t=&u=&urw=").enqueue(new Callback<ResponseBody>()

我最后的url是:https://so.csdn.net/so/search/ip1?q=%E5%8A%A8%E6%80%81%E9%85%8D%E7%BD%AEURL%E5%9C%B0%E5%9D%80%40Path%20retrofit&t=&u=&urw=

这是因为在Query接口中定义的是@GET(“ip1”),所以最后的URL中的路径部分是"ip1",而不是"ip"。同时,在调用getbody方法时,传入的参数是一个字符串,而该参数实际上是用作查询参数的值,会被自动拼接到URL中。因此,最后的URL就是"https://so.csdn.net/so/search/ip1?q=%E5%8A%A8%E6%80%81%E9%85%8D%E7%BD%AEURL%E5%9C%B0%E5%9D%80%40Path%20retrofit&t=&u=&urw=“。](https://so.csdn.net/so/search/ip1?q=动态配置URL地址@Path retrofit&t=&u=&urw=”,因为在Query接口中定义的是@GET(“ip1”),所以最后的URL中的路径部分是"ip1",而不是"ip"。同时,在调用getbody方法时,传入的参数是一个字符串,而该参数实际上是用作查询参数的值,会被自动拼接到URL中。因此,最后的URL就是"https://so.csdn.net/so/search/ip1?q=动态配置URL地址@Path retrofit&t=&u=&urw="。)

3.1.1.2POST注解

POST注解的时候

例如:

 @FormUrlEncoded
    @POST("ip")
    Call<WeatherBeans> requestWeatherBeans(
            @Field("app") String app,
            @Field("weaid") String weaid,
            @Field("appkey") String appkey,
            @Field("sign") String sign,
            @Field("format") String format);
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://api.k780.com/")
        .addConverterFactory(GsonConverterFactory.create())
        .build();
postField netService = retrofit.create(postField.class);
Call<WeatherBeans> call = netService.requestWeatherBeans("weather.future","1","10003","b59bc3ef6191eb9f747dd4e83c99f2a4","json");

这里的传入的url是:

http://api.k780.com/ip


如果写成

@FormUrlEncoded
    @POST("/")
    Call<WeatherBeans> requestWeatherBeans(
            @Field("app") String app,
            @Field("weaid") String weaid,
            @Field("appkey") String appkey,
            @Field("sign") String sign,
            @Field("format") String format);
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://api.k780.com/")
        .addConverterFactory(GsonConverterFactory.create())
        .build();
postField netService = retrofit.create(postField.class);
Call<WeatherBeans> call = netService.requestWeatherBeans("weather.future","1","10003","b59bc3ef6191eb9f747dd4e83c99f2a4","json");

这里的传入的url是:

http://api.k780.com/

而:

Call<WeatherBeans> call = netService.requestWeatherBeans("weather.future","1","10003","b59bc3ef6191eb9f747dd4e83c99f2a4","json")

这段代码并不是给url传递参数,这是因为在使用 @Field 注解时,Retrofit 会将这些参数转换为 “application/x-www-form-urlencoded” 的格式,然后作为请求体发送到服务器。也就是说,这些参数并不是直接附加到 URL 上,而是作为请求体的一部分发送到服务器。因此,即使在 @POST("/") 的情况下,这些参数也不会直接附加到 URL 上。

如果您将@POST("/")更改为@GET("/")并且不使用@FormUrlEncoded,则@Field注释将无效。此时,请求参数将被编码到URL的查询部分中,而不是通过请求正文发送。


3.2传输数据类型为JSON字符串:@Body

@Body会将请求参数放到请求体中,所以适用于POST请求

@Body标签不能和@FormUrlEncoded或@Multipart标签同时使用,会报错

public interface body {
    @POST("/")
    Call<ResponseBody> requestWeatherBeans(
            @Body bodytext bodytext);
}
public class bodytext {
    private String app;
    private String weaid;
    private String appkey;
    private String sign;
    private String format;

    public bodytext(String app,String weaid,String appkey,String sign,String format) {
        this.app = app;
        this.appkey = appkey;
        this.format = format;
        this.sign = sign;
        this.weaid = weaid;
    }
}
Retrofit retrofit1 = new Retrofit.Builder().baseUrl("http://api.k780.com/").
        addConverterFactory(GsonConverterFactory.create())
        .build();
body body = retrofit1.create(com.example.retrofit_0.post.body.class);
bodytext bodytext = new bodytext("weather.future","1","10003","b59bc3ef6191eb9f747dd4e83c99f2a4","json");
Call<ResponseBody>call1 = body.requestWeatherBeans(bodytext);
call1.enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
        if(response.isSuccessful()){
            try {
                body1.setText(response.body().string());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {

    }
});

最后成功

感觉没啥说的

3.3单个文件上传:@Part

  • Multipart注解表示允许多个@Part
  • updateUser方法的第一个参数是准备上传的图片文件,使用了MultipartBody.Part
  • 第二个参数是RequestBody类型的,它用来传递简单的键值对
public interface UpLoadFileForPart {
    @                    
    @POST("user/photo")
    Call<User> updateUser(@Part MultipartBody.Part photo , @Part("description")RequestBody description);
}
File file = new File(Environment.getExternalStorageDirectory() , "Ning.png");
//根路径下,file的名字为NING.png
RequestBody photoRequestBody = RequestBody.create(MediaType.parse("image.png") ,file);
//最后这一句让Ning是一个image.png类型的
MultipartBody.Part photo = MultipartBody.Part.createFormData("photos" ,"Ning.png" , photoRequestBody);
//这一步是将图片文件转换为一个MultipartBody.Part类型的对象,以便于在Retrofit请求中使用。MultipartBody.Part可以包含一个文件或者表单字段,需要提供一个唯一的key(如“photos”)以及文件名(如“Ning.png”),并使用RequestBody类型的实例来描述文件的内容。在这个例子中,photoRequestBody就是一个RequestBody实例,它包含了文件的二进制内容和MIME类型。然后使用MultipartBody.Part.createFormData()方法将这些信息打包成一个MultipartBody.Part对象,传入updateUser()方法的photo参数中。
UpLoadFileForPart upLoadFileForPart = retrofit.create(UpLoadFileForPart.class);
Call<User> call1 = upLoadFileForPart.updateUser(photo , RequestBody.create(null , "Ning"));

@POST("user/photo") 表示请求的URL为 http://<base_url>/user/photo,其中 <base_url> 是在 Retrofit 的构造器中通过 baseUrl() 方法设置的基础 URL。

  1. @Part MultipartBody.Part photo:这是一个二进制文件,用于上传图片或文件。
  2. @Part(“description”) RequestBody description:这是一个字符串描述,用于描述上传的文件或图片。

MultipartBody.Part是一个封装了二进制数据的类,它包含了数据的Content-Type、文件名等信息,可以通过MultipartBody.Part.createFormData方法来创建。

RequestBody是一个抽象类,它代表了请求体的内容。在这个例子中,我们使用了它的子类,即okhttp3.RequestBody。我们可以使用RequestBody.create方法来创建RequestBody对象,然后将其作为@Part参数的值传递。

3.4多个文件上传:@PartMap

public interface UpLoadFileForPart {
    @Multipart
    @POST("user/photo")
    Call<User> updateUser(@PartMap Map<String,RequestBody>photo , @Part("description")RequestBody description);
}

4.消息报头(Header)

  • 在HTTP请求中,为了过滤掉不安全的访问、添加特殊加密的访问或者防止被攻击等,以便减轻服务器的压力和保证请求的安全,通常会在消息报头中携带一些特殊的消息头处理。
  • Retrofit提供了@Header来添加消息报头。添加消息报头有静态和动态两种方式

4.1静态

public interface SomeService {
    @GET("some/endpoint")
    @Headers("Accept-Encoding: application/json")
    Call<ResponseBody> getCarType();
} 

使用Headers注解来添加消息报头
如果想要添加多个消息报头,则可以使用{}包起来

public interface SomeService {
    @GET("some/endpoint")
    @Headers({
        "Accept-Encoding: application/json"
        "User-Agent: MoonRetrofit"
        })
    Call<ResponseBody> getCarType();
} 

4.2动态

使用@Header注解,通过getCarType方法来动态添加。外界传参进来

public interface SomeService {
    @GET("some/endpoint")
    Call<ResponseBody> getCarType(@Header("Location") String location);
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值