Retrofit的基本post,get请求

一.简介

Retrofit是Square公司开发的一款针对Android网络请求的框架,Retrofit2底层基于OkHttp实现。

本文介绍的是Retrofit2.0+版本的使用

一个完整的Get请求

1.创建业务请求接口,具体代码如下:

获取北京天气的接口,get请求,参数是key和cityname,返回数据是WeatherData

 public interface WeatherService{
        @GET("weather/index")
        Call getWeatherData(@Query("cityname") String cityname,@Query("key") String key);
 }

注:@GET注解就表示get请求,@Query表示请求参数,将会以key=value的方式拼接在url后面

Query非必填,如果请求参数非必填,可以传null,如果key非必填可以写成:

Call call = service.getWeatherData("北京", null);

2.创建一个Retrofit的示例,并完成相应的配置

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("http://v.juhe.cn/")
    .addConverterFactory(GsonConverterFactory.create())
    .build();

WeatherService service = retrofit.create(WeatherService.class);

这里的baseUrl就是网络请求URL相对固定的地址,一般包括请求协议(如Http)、域名或IP地址、端口号等,addConverterFactory方法表示需要用什么转换器来解析返回值,GsonConverterFactory.create()表示调用Gson库来解析json返回值。

3.调用请求方法,并得到Call实例

Call call = service.getWeatherData("北京", "5c2dd6dd912ba8336889b0325689f809");

注:Call其实在Retrofit中就是行使网络请求并处理返回值的类

4.使用Call实例完成同步或异步请求

同步请求:
WeatherData response = call.execute().body();
注:必须在子线程中执行,否则会报错

异步请求:

  call.enqueue(new Callback() {
    @Override
    public void onResponse(Call call, Response response) {

        mResault.setText(response.body().toString());
    }
    @Override
    public void onFailure(Call call, Throwable t) {
        Toast.makeText(MainActivity.this, "请求数据失败", Toast.LENGTH_SHORT).show();
    }
 });

二.使用

首先需要在build.gradle文件中引入需要的第三包,配置如下:

compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'

Get请求

@Query

Get方法请求参数都会以key=value的方式拼接在url后面,Retrofit提供了两种方式设置请求参数。第一种就是像上文提到的直接在interface中添加@Query注解,还有一种方式是通过Interceptor实现。

public class CustomInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        HttpUrl httpUrl = request.url().newBuilder()
            .addQueryParameter("token", "tokenValue")
            .build();
        request = request.newBuilder().url(httpUrl).build();
        return chain.proceed(request);
    }
}

addQueryParameter就是添加请求参数的具体代码,这种方式比较适用于所有的请求都需要添加的参数,一般现在的网络请求都会添加token作为用户标识,那么这种方式就比较适合。
创建完成自定义的Interceptor后,还需要在Retrofit创建client处完成添加

addInterceptor(new CustomInterceptor())
@QueryMap

如果Query参数比较多,那么可以通过@QueryMap方式将所有的参数集成在一个Map统一传递

public interface WeatherService
{
    @GET("weather/index")
    Call getWeatherData(@QueryMap Map params);
}

调用的时候将所有的参数集合在统一的map中即可

Map params = new HashMap<>();
params.put("cityname", "北京");
params.put("key", "5c2dd6dd912ba8336889b0325689f809");
Call call = service.getWeatherData(params);

Query集合

如果需要添加相同Key值,但是value却有多个的情况,一种方式是添加多个@Query参数,还有一种简便的方式是将所有的value放置在列表中,然后在同一个@Query下完成添加,实例代码如下:

public interface WeatherService
{
    @GET("weather/index")
    Call getWeatherData(@Query("name") List name);
}

相当于

Map params = new HashMap<>();
params.put("name", "北京");
params.put("name", "南京");
@Path

如果请求的相对地址也是需要调用方传递,那么可以使用@Path注解

@GET("weather/{name}")
Call getWeatherData(@Path("name") String name);
Call call = WeatherService.getWeatherData("北京");

注:@Path可以用于任何请求方式,包括Get、Post、Put、Delete等

Post请求

@Field

Post请求需要把请求参数放置在请求体中,而非拼接在url后面

public interface NewsDataService
{
    @FormUrlEncoded
    @POST("news/list")
    Call getNewsData(@Field("key") String key);
}

注:@FormUrlEncoded将会自动将请求参数的类型调整为application/x-www-form-urlencoded,假如key传递的参数为”435678”,那么最后得到的请求体就是

key=”435678”

@Field注解将每一个请求参数都存放至请求体中,还可以添加encoded参数,该参数为boolean型,具体的用法为

@Field(value = “key”, encoded = true) String key 

encoded参数为true的话,key-value-pair将会被编码,即将中文和特殊字符进行编码转换

@FieldMap

假如有多个请求参数,这个时候就可以用FieldMap

@FormUrlEncoded
@POST("news/list")
Call getNewsData(@FieldMap Map params);
Map params = new HashMap<>();
params.put("key", "32451");
params.put("name", "北京");
params.put("startindex", 1);
params.put("endindex", 10);
Call getNewsData(params);
@Body

如果Post请求参数有多个,那么统一封装到类中应该会更好,这样维护起来会非常方便

@FormUrlEncoded
@POST("news/list")
Call getNewsData(@Body Entity entity);


public class Entity {
    public String key;
    public String name;
    public int startindex;
    public int endindex;
}

//get和set方法…..

Entity entity = new Entity();
entity.setKey("32451");
entity.setName("北京");
entity.setStartindex(1);
entity.setEndindex(10);

Call getNewsData(entity);

上传文件

单张图片上传并携带参数

public interface UploadFileService
{
    @Multipart
    @POST("uploaad/file")
    Call  uploadFile(@Part MultipartBody.Part photo, @Part("description") RequestBody description);
}

上传代码

Retrofit retrofit = new Retrofit.Builder()
.baseUrl(“http://192.168.1.62:8080/UploadFile/“)
.addConverterFactory(GsonConverterFactory.create())
.build();

    UploadFileService service = retrofit.create(UploadFileService.class);

    //sd卡下imgs下的一张图片(拍照或者从相册中选择都可以获取到图片文件)
    File file = new File(Environment.getExternalStorageDirectory()+"/imgs", "demo.png");

    //设置Content-Type:application/octet-stream
    RequestBody photoRequestBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);

    //设置Content-Disposition:form-data; name="photo"; filename="demo.png"
    MultipartBody.Part photo = MultipartBody.Part.createFormData("photo", file.getName(), photoRequestBody);

    //添加参数description,并且是文本类型
    RequestBody description = RequestBody.create(MediaType.parse("text/plain"), "图片的描述");

    Call mCall = service.uploadFile(photo, description);

    mCall.enqueue(new Callback() {
        @Override
        public void onResponse(Call call, Response response) {

            Toast.makeText(MainActivity.this, "上传成功", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onFailure(Call call, Throwable t) {
            Toast.makeText(MainActivity.this, "上传失败", Toast.LENGTH_SHORT).show();
        }
    });

多张图片上传并携带参数

@Multipart
@POST("uploaad/files")
Call uploadfiles(@PartMap Map images, @Part("description") RequestBody description)

上传代码

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("http://192.168.1.68:8080/")
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    UploadFileService service = retrofit.create(UploadFileService.class);
    //sd卡下imgs下的两张图片(拍照或者从相册中选择都可以获取到图片文件)
    File file1= new File(Environment.getExternalStorageDirectory()+"/imgs", "demo1.png");
    File file2 = new File(Environment.getExternalStorageDirectory()+"/imgs", "demo2.png");

    RequestBody photoRequestBody1 = RequestBody.create(MediaType.parse("application/octet-stream"), file1);
    RequestBody photoRequestBody2 = RequestBody.create(MediaType.parse("application/octet-stream"), file2);
    RequestBody description = RequestBody.create(MediaType.parse("text/plain"), "图片的描述");

    Map images = new HashMap();
    //添加file1
    images.put("images\"; filename=\""+file1.getName(), photoRequestBody1);
    //添加file2
    images.put("images\"; filename=\""+file2.getName(), photoRequestBody2);
    //添加图片描述
    images.put("description",  description);

    Call call = service.uploadfiles(images, description);
    call.enqueue(new Callback() {
        @Override
        public void onResponse(Call call, Response response)
        {
            Toast.makeText(MainActivity.this, "上传成功", Toast.LENGTH_SHORT).show();
        }
        @Override
        public void onFailure(Call call, Throwable t)
        {
            t.printStackTrace();
            Toast.makeText(MainActivity.this, "上传失败", Toast.LENGTH_SHORT).show();

        }
    });

三.添加自定义的Headers

静态方法

可以添加多个

public interface WeatherService
{
@Headers({
    "Accept: application/vnd.yourapi.v1.full+json",
    "User-Agent: zhoujian_retrofit"})
@GET("weather/index")
Call getWeatherData(@QueryMap Map params);
}

也可以通过Interceptor来定义静态请求头

public class CustomInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request original = chain.request();
        Request request = original.newBuilder()
            .header("User-Agent", "zhoujian_retrofit")
            .header("Accept", "application/vnd.yourapi.v1.full+json")
            .method(original.method(), original.body())
            .build();
        return chain.proceed(request);
    }
}

然后在OkHttp创建Client实例时,添加RequestInterceptor即可

HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.HEADERS);
.addInterceptor(new CustomInterceptor())
.addInterceptor(logging)
.connectTimeout(DEFAULT_TIMEOUT,
TimeUnit.SECONDS)
.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.build();
}
动态方法

@GET("weather/index")
Call getWeatherData(@Header("Accept") String Accept,
                             @Header("User-Agent") String zhoujian_retrofit,
                             @Query("cityname") String cityname, @Query("key") String key);

四.网络请求日志

Retrofit官方提供了一个很方便查看日志的Interceptor,你可以控制你需要的打印信息类型.

首先需要在build.gradle文件中引入logging-interceptor

compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'

同上文提到的CustomInterceptor一样,添加到OkHttpClient创建处即可

HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.HEADERS);
private static OkHttpClient getClient(){
    HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
    logging.setLevel(HttpLoggingInterceptor.Level.HEADERS);
    return new OkHttpClient.Builder()
            .addInterceptor(logging)
            .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
            .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
            .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
            .build();
}

HttpLoggingInterceptor提供了4中控制打印信息类型的等级,分别是NONE,BASIC,HEADERS,BODY

NONE:没有任何日志信息

BASIC:打印请求类型,URL,请求体大小,返回值状态以及返回值的大小

HEADERS:打印返回请求和返回值的头部信息,请求类型,URL以及返回值状态码

BODY:打印请求和返回值的头部和body信息

最常用的是BODY

logging.setLevel(HttpLoggingInterceptor.Level.HEADERS);

TAG设置为okhttp

 Log.i("okhttp","返回数据==="+mString);

你可能感兴趣的:(Android中级知识)