android 多么好用的retrofit

来源:互联网 发布:dm软件 编辑:程序博客网 时间:2024/06/13 09:30

retrofit简介

  1. retrofit来源
    retrofit是大名鼎鼎的Square公司开源的一个优秀的库,用来简化网络请求的,其中的有点不由分说,结合mvp模式使用更是会让你爱不释手。
    什么是mvp模式?点击mvp模式介绍

  2. retrofit优点

    ★ Retrofit使用注解方式,大大简化了我们的URL拼写形式,而且注解含义一目了然,简单易懂。定义网络业务接口Retrofit的网络请求都是写在一个接口中,并使用一定的注释如下面一组请求接口:注意接口中的每个方法的参数都需要使用标注,不采用标注将会报错。

    ```/** * Created by melo on 2017/3/6. * 定义数据接口 */public interface Api {    @GET(UrlConfig.VIDEO)    Call<VideoBean> getVideoData();    @POST("{path}?")    Call<HotBean> getHotData(@Path("path") String path, @QueryMap() Map<String, String> map);}```

    ★ Retrofit使用简单,结构层次分明,每一步都能清晰的表达出之所以要使用的寓意

    ★ Retrofit支持同步和异步执行,使得请求变得异常简单,只要调用enqueue/execute即可完成

    ★ Retrofit更大自由度的支持我们自定义的业务逻辑,如自定义Converters

    ★ Retrofit简化了网络请求流程,同时自己内部对OkHtttp客户端做了封装,同时2.x把之前1.x版本的部分不恰当职责都转移给OkHttp了(例如Log,目前用OkHttp的Interceptor来实现),这样的好处是职责清晰,Retrofit做自己该做的事儿。

    ★ Retrofit提供不同的Json Converter实现(也可以自定义),同时提供RxJava支持(返回Observable对象),配合Jackson(或者Gson)和RxJava,再加上Dagger2,你的效率至少可以提高一倍。


retrofit请求参数注解类型

  • @Query、@QueryMap
    @GET("type/actor")    Call<VideoBean> getVideoData(@Query("year") String y);    //这样做相当于url为 type/actor?year=y    @POST("{path}?")    Call<HotBean> getHotData(@Path("path") String path, @QueryMap() Map<String, String> map);    //假设map 内为 键值对key=a value=A  ,key=b value=B  ,    //这样做相当于url为path?a =A&b  =B
  • @Field
    //Post方式传递参数,同时在方法上添加@FormUrlEncoded,即以表单的方式传递参数.这里假 设获取注册用户    @FormUrlEncoded    @POST("resigeruser/message")    Call<ResigerUser> getResigerMsg(@Field("type") String allUsers);
  • @Path
    //就是url中的一个替代符号,比如这个api,全是妹子哦http://gank.io/api/data/福利/10/1    //解释下这个链接 福利对应类型type 10 对应每页返回的条数 1表示页码,就可以表示成    @GET("{type}/{amount}/{page}")    Call<List<User>> groupList(@Path("type")  String type , @Path("amount")  String amount , @Path("page")  String page,);   //如果还时不理解,不妨去试一试,就有体会了
  • @Part
     //用于文件上传,另外需要同时在方法上添加@Multipart,比如注册用户上传的头像    @Multipart    @PUT("resigeruser/headportrait ")    Call<ResigerUser>  submitHeadPortrait (@Part("headportrait ") RequestBody headportrait , @Part("description") RequestBody description);
  • @Header 和@Headers 就是单个头部和多个头部的意思,下面会有使用到。

retrofit使用

▲get请求

  1. 第一步在module中配置bulid.gradle
dependencies {    compile fileTree(dir: 'libs', include: ['*.jar'])    testCompile 'junit:junit:4.12'    compile 'com.android.support:appcompat-v7:25.3.1'    //okhttp+retrofit    compile 'com.squareup.okhttp3:okhttp:3.5.0'    compile 'com.squareup.retrofit2:retrofit:2.0.2'    //gson    compile 'com.squareup.retrofit2:converter-gson:2.0.2'}

添加依赖okhttp包和retrofit包,另外需要添加converter-gson包,retrofit的优点中已经介绍过这点,所以这个是不可缺少的。
2. 第二步定义retrofit访问的Api接口类

/** * Created by melo on 2017/3/6. * 定义数据接口 */public interface Api {     @GET(UrlConfig.SHEHUI)       Call<ShehuiBean> getString();}

可以清楚的看到上面的注解@GET就是用get请求的方式,返回的是一个ShehuiBean类型的结果
3. 第三步编写RetrofitHelper类

/** * Created by melo on 2017/3/6. * 定义retrofit类 */public class RetrofitHelper {    private static volatile RetrofitHelper instance = null;    private RetrofitHelper() {    }    //创建单例    public static RetrofitHelper getInstance() {        if (instance == null) {            synchronized (RetrofitHelper.class) {                if (instance == null) {                    instance = new RetrofitHelper();                }            }        }        return instance;    }    //创建OkHttpClient 对象    public OkHttpClient createHttpClient() {        OkHttpClient client = new OkHttpClient.Builder()                .connectTimeout(60 * 1000, TimeUnit.MILLISECONDS)                .readTimeout(60 * 1000, TimeUnit.MILLISECONDS)                .build();        return client;    }//创建Retrofit 对象    public Retrofit createRetrofit() {        return new Retrofit.Builder()                .baseUrl(UrlConfig.BASE_URL)                .client(createHttpClient())                //gson解析要加                .addConverterFactory(GsonConverterFactory.create(createGson()))                //rxjava 需要添加                //.addCallAdapterFactory(RxJavaCallAdapterFactory.create())                .build();    }//创建Api 对象    public Api getService() {        Retrofit retrofit = createRetrofit();        Api apiService = retrofit.create(Api.class);        return apiService;    }    /**     * @return     */    public Gson createGson() {        return new GsonBuilder()                .serializeNulls()                .enableComplexMapKeySerialization()//                .setDateFormat("")                .create();    }}

这个类中的方法就不用多说了
4. 最后再看我们的MainActivity代码也不多

public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        RetrofitHelper.getInstance().getService().getString().enqueue(new Callback<ShehuiBean>() {            @Override            public void onResponse(Call<ShehuiBean> call, Response<ShehuiBean> response) {                if (response.isSuccessful()){                    ShehuiBean shehuiBean= response.body();                    Log.i("tag",shehuiBean.getTitle());                }            }            @Override            public void onFailure(Call<ShehuiBean> call, Throwable t) {                Log.i("tag","下载失败");            }        });    }}

这里用了enqueue异步请求,以为耗时操作基本都是异步调度的嘛

这是基本的get请求


▲ post请求
post请求 和get在请求方式上的不同之处在于post将各种参数都放在包体中,这样做自然就是比较安全,不至于想get方式一样请求参数都暴露在外部

接下来看我们如何操作的呢

  1. 第一步,在Api接口类中增加post请求方法
/** * Created by melo on 2017/3/6. * 定义数据接口 */public interface Api {    @GET(UrlConfig.SHEHUI)    Call<ShehuiBean> getString();    @POST("{path}?")    Call<GuoNeiBean> getGuoNeiData(@Path("path") String path, @QueryMap() Map<String, String> map);}

对于请求体不确定的参数赢{}?的方式,比如如下链接http://v.juhe.cn/toutiao/index?type=guonei&key=723060051cc0b5baa348a8024b1bb7e1
此处的index页码是不确定的,就可以用上述方式改造。
2. 第二步直接就可以去请求网络了,先看代码

public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //社会  get请求        RetrofitHelper.getInstance().getService().getString().enqueue(new Callback<ShehuiBean>() {            @Override            public void onResponse(Call<ShehuiBean> call, Response<ShehuiBean> response) {                if (response.isSuccessful()){                    ShehuiBean shehuiBean = response.body();                    Log.i("tag", "社会:" +shehuiBean.getResult().getData().get(0).getTitle());                }            }            @Override            public void onFailure(Call<ShehuiBean> call, Throwable t) {                Log.i("tag","下载失败");            }        });        //国内 post请求        HashMap<String, String> map = new HashMap<>();        map.put("type", "guonei");        map.put("key", "723060051cc0b5baa348a8024b1bb7e1");        RetrofitHelper.getInstance().getService().getGuoNeiData(UrlConfig.GUONEI,map).enqueue(new Callback<GuoNeiBean>() {            @Override            public void onResponse(Call<GuoNeiBean> call, Response<GuoNeiBean> response) {                if (response.isSuccessful()) {                    GuoNeiBean guoNeiBean = response.body();                    Log.i("tag", "国内:" + guoNeiBean.getResult().getData().get(0).getTitle());                }            }            @Override            public void onFailure(Call<GuoNeiBean> call, Throwable t) {            }        });    }}

可以看到我们用map将所请求的参数以键值对的形式装了起来,还可以通过传入页面index去控制所要下载的数据

▲ 上传图片
这里先留着吧,因为我自己没有搭建本地的服务,后面有机会在补充
想了解这部分点击此处

拦截器???

以上两种请求都是基本的用法,但是一般项目中post请求除了键值对,也还会遇到json、xml的请求,后台也做了约束,约束其上传格式为json/xml,防止乱入,一般会需要添加头文件headers

方式一:在Api接口类的方法中注解添加

public interface Api {    @GET(UrlConfig.SHEHUI)    Call<ShehuiBean> getString();    @Headers({"Content-Length:200","Content-type:application/json",})//分别为 请求内容长度限制,请求限制为json格式    @POST("{path}?")    Call<GuoNeiBean> getGuoNeiData(@Path("path") String path, @QueryMap() Map<String, String> map);}

上述添加的请求头不一定在此处合适,但是用法雷同。

方式二:添加拦截器,在拦截器内添加header,便于统一管理

/** * Created by melo on 2017/8/9. * header拦截器 */public class NetInterceptor implements Interceptor{    @Override    public Response intercept(Chain chain) throws IOException {        Request.Builder builder = chain.request().newBuilder();        Request requst = builder.addHeader("Content-type", "application/json")                .addHeader("Content-Length","300")                .build();        return chain.proceed(requst);    }}

至于需要增加什么样的限制,继续addHeader就可以。

接下来就需要修改RetrofitHelper中Httpclient的构建

 public OkHttpClient createHttpClient() {        OkHttpClient client = new OkHttpClient.Builder()                .connectTimeout(60 * 1000, TimeUnit.MILLISECONDS)                .readTimeout(60 * 1000, TimeUnit.MILLISECONDS)                //添加拦截器                .addInterceptor(new NetInterceptor())                .build();        return client;    }

然后去掉Api中刚才方式一添加的Headers就可以了,Api方法中就可以用Body体去传json类型的bean类了(此处不能直接在方法内传string类型的字符串哦,需自行体会)

github:demo链接