Android框架学习笔记03Retrofit框架

来源:互联网 发布:淘宝信用查询网 编辑:程序博客网 时间:2024/04/30 18:29

  前面我们学习过了Android网络开发中的Okhttp框架和Asynchttpclient框架,这一篇我们学习一个非常强大的框架——Retrofit框架。Retrofit现在最新版本是2.1.0,Retrofit框架是Square公司推出来的,是在Okhttp基础上的进一步封装。

  在这里对Okhttp做一些说明:Okhttp是基于HTTP协议封装的,跟HttpClient、HttpUrlConnection的职责是一样的,虽然Okhttp也可以开线程,但它是更多偏向于真正的网络通信。Okhttp是基于NIO和OKio的,这里可能很多人不明白什么是IO、NIO和Okio,这里做一个简单的解释:IO和NIO是Java的概念,IO是一种阻塞式的数据读取,举个例子:我向网络中请求数据,程序就一种在等待,等到网络中返回数据并解析好了,程序才往下执行,这种就是阻塞式的;而NIO则是非阻塞式的,还是刚才那个例子,向网络请求数据,但是程序继续执行,等到数据返回和处理完才通知我,然后通过回调处理,这种就是非阻塞式的,非阻塞式的效率比阻塞式的高。而Okio是Square公司在IO和NIO基础上封装的一个更高效、更简单的数据处理库。

下面我们介绍一下Retrofit这个框架

概述

  Retrofit框架是基于Okhttp封装的,在1.0版本的时候是默认采用Okhttp通信,不过在没有添加Okhttp依赖的时候也可以采用自带的网络请求通信,解析数据方式是Gson(一个Google推出的Json数据解析框架,后面我们会介绍),所以我们需要添加Gson的依赖。但是在2.0后的版本中,Retrofit是必须要采用Okhttp请求,还有请求返回数据的解析也不是Gson,需要我们自己手动指定。

  Retrofit是通过注解将HTTP请求转化为Java接口,那么,我们了解一下Retrofit提供有哪些注解?

请求方式的注解

  • DELETE:构建一个DELETE请求
  • GET:构建一个GET请求
  • HTTP:可以代替其它的任意一种
  • OPTIONS:构建一个OPTIONS请求
  • PATCH:构建一个PATCH请求
  • POST:构建一个POST请求
  • PUT:构建一个PUT请求

上面列出的都是Retrofit2.0提供的网络请求方式的注解,其中,我们可以通过HTTP这个注解自定义一个请求方式,例如:

 interface Service {   @HTTP(method = "CUSTOM", path = "custom/endpoint/")   Call<ResponseBody> customEndpoint(); }

甚至HTTP注解也可以用于发送一个DELETE请求方式的请求体,例如:

interface Service {   @HTTP(method = "DELETE", path = "remove/", hasBody = true)   Call<ResponseBody> deleteObject(@Body RequestBody object); }

标记注解

  • FormUrlEncoded注解:与@Field或者@FieldMap一起使用,上传表单数据
  • Multipart注解:与@Part一起使用
  • Streaming注解:用于下载大文件

参数注解

  • Body注解::用于POST请求体,将实例对象根据转换方式转换为对应的json字符串参数,这个转化方式是GsonConverterFactory定义的。
  • Field注解:@Field和@FormURLEncoded一起使用,表示提交一个表单数据给服务器,我们都知道,表单数据是以键值对的形式存在,所以,@Field注解中的参数字符串为“键”,而被@Field标注的参数值为 “值”,例如:

     @FormUrlEncoded @POST("/list") Call<ResponseBody> example(@Field("name") String... names);
  • FieldMap注解:这个注解跟上面的@Field注解差不多,也是和@FieldURLEncoded一起使用。注解的是一个Map,键作为表单数据的”键”,值作为表单数据的”值”,例如

    @FormUrlEncoded@POST("/things")Call<ResponseBody> things(@FieldMap Map<String, String> fields);
  • Part注解:与@PartMap一样

  • PartMap注解:用于POST文件上传,其中@Part MultipartBody.Part代表文件,@Part(“key”)RequestBody代表参数,需要添加@Multipart表示支持文件上传的表单,Content-Type: multipart/form-data,例如:

    @Multipart@POST("/upload")Call<ResponseBody> upload(@Part("file") RequestBody file,@PartMap Map<String, RequestBody> params);
  • Query注解:表示查询参数,非常简单

  • QueryMap注解:查询参数,用于GET查询,需要注意的是@QueryMap可以约定是否需要encode

其它注解

  • Path注解:URL占位符,我们看一个例子:

    @GET("/image/{id}")Call<ResponseBody> example(@Path("id") int id);@GET("/user/{name}")Call<ResponseBody> encoded(@Path("name") String name);就是将例子中用@Path标注的参数用来替换服务器地址中使用“{}”括起来的字符串,简单说就是,这是一个占位符。但是注意的是,不能替换URL中的字符串,例如:在http://www.hitomis.com/user.do?action=findUser&username="zuck"中,不能替换action=findUser&username="zuck"路径中的内容
  • Url注解:使用全路径复写baseUrl,用于不是同一baseUrl的场景

  • Header注解:设置请求头,可以不设置。设置的话就是@Header里面注解参数为”键”,被@Header注解的参数作为”值”,例如:

     @GET("/")Call<ResponseBody> foo(@Header("Accept-Language") String lang);
  • Headers注解:用于修饰方法,用于设置多个Header值

  • HeaderMap注解:与Header类似

好了,Retrofit就简单介绍到这里,下面我们还是学习一下怎么使用这个框架!

使用

Android Studio使用需要在Gradle中添加依赖,建议先去GitHub上获取最新的依赖,在这里给出Retrofit的GitHub地址和官网地址:

GItHub地址:https://github.com/square/retrofit

官网地址:http://square.github.io/retrofit/

compile 'com.squareup.retrofit2:retrofit:2.1.0'

这是Gradle依赖,我们需要用到java/Json转换器工厂,所以需要添加转换器的依赖,可以直接在AS里面搜索最新,包括上面的Retrofit依赖也可以在AS里面搜索

compile 'com.squareup.retrofit2:converter-gson:2.1.0'

如果你想用RxJava支持的适配器的话,需要添加适配器的依赖,也可以直接在AS里面搜索,这里我们没有用到,所以就不需要添加支持RxJava适配器的依赖。

简单描述一下使用Retrofit框架的基本步骤:

  1. 第一步当然就是添加依赖了,Android开发的话基本都是用Gradle的,如果是Java可以用Maven。

  2. 第二步则是定义一些接口,Retrofit是面向接口编程的。

  3. 第三步是创建Retrofit对象,一般是使用Builder模式创建这个对象

  4. 第四步就是使用Retrofit。

上面列出的就是使用Retrofit的基本步骤,下面我们具体使用一下这个强大的网络请求框架

我们说过Retrofit是面向接口编程的,所以使用之前我们需要定义一些我们用到的接口,那么我们先看一下我们定义的接口:

package com.example.frame.common;import com.example.frame.bean.ContributorsBean;import java.util.List;import okhttp3.MultipartBody;import okhttp3.ResponseBody;import retrofit2.Call;import retrofit2.http.Field;import retrofit2.http.FormUrlEncoded;import retrofit2.http.GET;import retrofit2.http.Multipart;import retrofit2.http.POST;import retrofit2.http.Part;import retrofit2.http.Query;import retrofit2.http.Url;/** * Created by :Huawen * Created time : 2016/9/22 16:15 * Description : * Github: https://github.com/Devin1102 */public interface RetrofitAPI {/** * 普通的请求 * * @return */@GET("repos/square/retrofit/contributors")Call<List<ContributorsBean>> getData();/** * 查询 * * @param username * @return */@GET("sayHello")Call<ResponseBody> getQuery(@Query("username") String username);/** * 上传文件 * * @param fileUrl * @return */@GETCall<ResponseBody> downloadFiel(@Url String fileUrl);/** * 上传文件 * * @param description * @param file * @return */@Multipart@POST("upload")Call<ResponseBody> uploadFile(@Part("description") ResponseBody description, @Part MultipartBody.Part file);/** * 上传表单数据 * * @param username * @param password * @return */@FormUrlEncoded@POST("sayHello")Call<ResponseBody> postForm(@Field("username") String username, @Field("password") String password);}

除了接口之外,我们还将Retrofit对象的获取封装了,看一下封装的代码:

public class RetrofitService { protected Retrofit getRetrofit() {    Retrofit retrofit = new Retrofit.Builder()            .baseUrl(UrlUtils.GET_BASE_URL)            .addConverterFactory(GsonConverterFactory.create())            .build();    return retrofit; }    public RetrofitAPI createRetrofitAPI() {        return getRetrofit().create(RetrofitAPI.class);    }}

这里也没有什么好解析,我们这里没有添加OkhttpClient端,Retrofit会自动创建一个,当然我们也可以自己手动设置一个。

使用Retrofit实现简单的GET请求

使用Retrofit框架完成GET请求非常简单,我们先看一下代码:

 private void retrofitGet() {    Call<List<ContributorsBean>> call = mRetrofit.getData();    call.enqueue(new Callback<List<ContributorsBean>>() {        @Override        public void onResponse(Call<List<ContributorsBean>> call, Response<List<ContributorsBean>> response) {            Log.i(TAG, "onResponse请求成功");            List<ContributorsBean> beans = response.body();            for (ContributorsBean contributorsBen : beans) {                Log.i(TAG, "onResponse" + contributorsBen);            }        }        @Override        public void onFailure(Call<List<ContributorsBean>> call, Throwable t) {            Log.i(TAG, "onFailure请求失败");        }    });}

这里对应的接口里面的GET请求,里面我们没有设置参数。这种请求跟Okhttp框架请求方式差不多,使用的也是异步的请求。

Retrofit实现Query参数请求

这个是一个简单的GET请求,不过设置一些参数,上面我们说过@Query和@QueryMap是用于GET请求的设置参数,我们看一下具体的代码:

private void retrofitGetQuery() {    Call<ResponseBody> call = mRetrofit.getQuery("Devin");    call.enqueue(new Callback<ResponseBody>() {        @Override        public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {            Log.i(TAG, getResources().getString(R.string.req_success));        }        @Override        public void onFailure(Call<ResponseBody> call, Throwable t) {            Log.i(TAG, getResources().getString(R.string.req_failed));        }    });}

这里我们设置一个参数,与接口一致。

Retrofit实现POST上传表单数据

我们在做实际项目的时候,需要向服务器传递一些表单数据,比如登录、注册功能的时候,Retrofit也给我们提供了实现表单数据上传的方法,我们看一下具体的例子:

private void retrofitPostForm() {    Call<ResponseBody> call = mRetrofit.postForm("Devin", "Devin");    call.enqueue(new Callback<ResponseBody>() {        @Override        public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {            Log.i(TAG, getResources().getString(R.string.req_success));        }        @Override        public void onFailure(Call<ResponseBody> call, Throwable t) {            Log.i(TAG, getResources().getString(R.string.req_failed));        }    });}

设置表单数据上传的时候需要在接口中设置@FormUrlEncoded这个方法标记,通过@Field或者@FieldMap实现设置数据。

Retrofit实现文件下载

文件下载是经常使用的网络操作,比如图片和视频下载、APP更新等。我们看一下Retrofit框架提供的文件下载功能:

 private void retrofitDownloadFile() {    Call<ResponseBody> call = mRetrofit.downloadFiel("http://repo1.maven.org/maven2/com/squareup/retrofit2/retrofit/2.1.0/retrofit-2.1.0.jar");    call.enqueue(new Callback<ResponseBody>() {        @Override        public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {            InputStream is = response.body().byteStream();            try {                FileOutputStream fos = new FileOutputStream(new File("/sdcard/retrofit-2.1.0.jar"));                byte[] bytes = new byte[1024];                int len = 0;                while ((len = is.read(bytes)) != -1) {                    fos.write(bytes, 0, len);                }                fos.flush();            } catch (FileNotFoundException e) {                e.printStackTrace();            } catch (IOException e) {                e.printStackTrace();            }            Log.i(TAG, "onResponse" + getResources().getString(R.string.req_success));        }        @Override        public void onFailure(Call<ResponseBody> call, Throwable t) {            Log.i(TAG, "onFailure" + getResources().getString(R.string.req_failed));        }    });}

在定义文件下载接口的时候,我们设置了@Url参数,这个是复写BaseUrl的,用于我们不使用baseUrl的情况,里面被@Url标志的数据是字符串类型,就是文件下载的URL。然后下载成功之后,以读流的形式将文件保存起来。

Retrofit实现文件上传

文件上传也是经常使用的功能,我们看一下Retrofit框架实现文件上传的功能:

private void retrofitUploadFile() {    String descriptionString = "UploadFile";    ResponseBody description = ResponseBody.create(MediaType.parse("multipart/form-data"), descriptionString);    RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), new File("/sdcard/retrofit-2.1.0.jar"));    MultipartBody.Part body = MultipartBody.Part.createFormData("picture", "retrofit-2.1.0.jar", requestFile);    Call<ResponseBody> call = mRetrofit.uploadFile(description, body);    call.enqueue(new Callback<ResponseBody>() {        @Override        public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {            Log.i(TAG, "onResponse" + getResources().getString(R.string.req_success));        }        @Override        public void onFailure(Call<ResponseBody> call, Throwable t) {            Log.i(TAG, "onFailure" + getResources().getString(R.string.req_failed));        }    });}

文件上传需要在接口中设置@Multipart标记,在接口中我们设置了两个参数:@Part(“description”) ResponseBody description, @Part MultipartBody.Part file,我们需要构建两个参数,然后实现上传。

以上是我对Retrofit框架的基本理解和具体的使用,可能写法不是很好,如果大家有更好的写法,欢迎大家留言交流。

上面Demo已经上传到GitHub了,当然还有其它框架的使用Demo,Demo的GitHub地址:https://github.com/Devin1102/AndroidFrameDemo

0 0
原创粉丝点击