retrofit简介
retrofit来源
retrofit是大名鼎鼎的Square公司开源的一个优秀的库,用来简化网络请求的,其中的有点不由分说,结合mvp模式使用更是会让你爱不释手。
什么是mvp模式?点击mvp模式介绍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请求
- 第一步在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方式一样请求参数都暴露在外部
接下来看我们如何操作的呢
- 第一步,在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类型的字符串哦,需自行体会)