您的位置:首页 > 理论基础 > 计算机网络

Retrofit 最简单的快速入门及自己封装

2017-01-10 23:22 381 查看

简单介绍及官方文档的坑

官方文档 http://square.github.io/retrofit/

Retrofit是Square公司开发的一款针对Android网络请求的框架,Retrofit2底层基于OkHttp实现的,OkHttp现在已经得到Google官方认可,大量的app都采用OkHttp做网络请求

Retrofit也就成了最火的网络请求框架之一,想着来研究一下Retrofit了…先看了看官方文档,发现各种坑,Retrofit是结合着注解来做的,思路新颖,但是不符合大部分开发程序员的思维习惯,一开始使用的时候,不太适应…附上官方文档的介绍

Retrofit turns your HTTP API into a Java interface.

public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
The Retrofit class generates an implementation of the GitHubService interface.

Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();

GitHubService service = retrofit.create(GitHubService.class);
Each Call from the created GitHubService can make a synchronous or asynchronous HTTP request to the remote webserver.

Call<List<Repo>> repos = service.listRepos("octocat");


快速入门,从Hello 百度走起

想快速入门Retrofit,我们最简单的想法是能请求一下www.baidu.com,然后将信息打印一下,但是发现在Retrofit入门的时候,访问www.baidu.com竟然成了奢求…,大部分的文章都是模仿着官方文档来写的…

先一起来写一个访问百度,展示数据的示例

第一步:gradle文件中进行配置

compile 'com.squareup.retrofit2:retrofit:2.0.0-beta2'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta2'
compile 'com.squareup.retrofit2:converter-scalars:2.0.0'


第二步:定义一个接口,接口中使用注解注明请求方式,及对应的请求路径

public interface DataService {
//指定get请求方式  指定路径 有时候路径除了baseUrl还有一部分比如 http://write.blog.csdn.net/mdeditor //http://write.blog.csdn.net/ 一般是baseUrl
//而 mdeditor是相对路径的
@GET
Call<String> baidu(@Url String url);
}


第二步:进行请求

//创建Retrofit对象
Retrofit retrofit = new Retrofit.Builder()
//指定baseurl,这里有坑,最后后缀出带着“/”
.baseUrl("http://www.baidu.com/")
//设置内容格式,这种对应的数据返回值是String类型
.addConverterFactory(ScalarsConverterFactory.create())
//定义client类型
.client(new OkHttpClient())
//创建
.build();
//通过retrofit和定义的有网络访问方法的接口关联
DataService dataService = retrofit.create(DataService.class);
//在这里又重新设定了一下baidu的地址,是因为Retrofit要求传入具体,如果是决定路径的话,路径会将baseUrl覆盖掉
Call<String> baidu = dataService.baidu("http://wwww.baidu.com");
//执行异步请求
baidu.enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {
Toast.makeText(MainActivity.this,  response.body(), Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(Call<String> call, Throwable t) {

}
});


通过上述代码,咱们就可以完整的看见百度的html界面了,算是对Retrofit做一个入门

其他请求-QQ吉凶测试

第三方网站聚合数据上的测试地址,key有可能过期,大家测的时候可以自己申请key 官网 https://www.juhe.cn

http://japi.juhe.cn/qqevaluate/qq?key=96efc220a4196fafdfade0c9d1e897ac&qq=295424589

返回数据内容

{"error_code":0,"reason":"success","result":{"data":{"conclusion":"[大吉+官运+财运+才艺]如龙得云,青云直上,智谋奋进,才略奏功","analysis":"欲望难足希望高,计谋成功财力豪,猜疑嫉妒性自改,如龙乘云势运开。智能超人贯彻大志,富贵无比,不甘寂寞,叱吒风云之大吉数,但容易发生牢骚及贪心、欲望太多而永不知足,为其缺点。切忌沉迷投机,可免贻误前程。"}}}


对于Retrofit可以直接生成对应的json

第一步:生成对应的Bean,例如 QQData

第二步:在接口中定义请求方法

GET请求

请求相对路径

参数内容

Call代表是一个请求

public interface DataService {
@GET("/qqevaluate/qq")
Call<QQData> getQQData(@Query("key") String appkey, @Query("qq") String qq);
}


第三步:开始请求

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

final Call<QQData> qqData = dataService.getQQData("96efc220a4196fafdfade0c9d1e897ac", "11111111");
qqData.enqueue(new Callback<QQData>() {
@Override
public void onResponse(Response<QQData> response, Retrofit retrofit) {

String reason = response.body().getReason();

Toast.makeText(MainActivity.this, response.body().getReason(), Toast.LENGTH_SHORT).show();
}

@Override
public void onFailure(Throwable t) {
Toast.makeText(MainActivity.this, "--" + t.getMessage().toString(), Toast.LENGTH_SHORT).show();
}
});


以上是Retrofit的简单应用,当然对于Retrofit还有一些其他的方式

///https://zhidao.baidu.com/daily/view
//路径拼接的形式,v代表是其中的一个参数,可以在这个位置进行拼接
@GET("daily/{v}")
Call<String> baiduzhidao(@Path("v") String v);
//在注解中指定路径,定义相对应的参数的集合
@GET("qqevaluate/qq")
Call<QQData> getQQDataMap(@QueryMap Map<String,String> map);
//对应Post请求,参数的注解是@Field
@POST("qqevaluate/qq")
Call<QQData>  postQQData(@Field("key") String key,@Field("qq") String qq);

//必须指定进行表单编码
@FormUrlEncoded
//指定参数是map形式 @FieldMap
@POST("qqevaluate/qq")
Call<QQData> postQQDataMap(@FieldMap Map<String,String> map);


自己封装一个简易的Retrofit请求

对于Retrofit,我们发现确实有一些特色,请求也比较简单,但是,当在一个大的项目中,不可能每一请求都到接口中声明一下。所以有必要进行简易的封装

封装一个简易的请求接口

public interface ProjectAPI {
//http://www.baidu.com/aaa?key=123&qq=aaa

@GET
Call<String> getMethod(@Url String url);

@FormUrlEncoded
@POST
Call<String> postMethod(@Url String url, @FieldMap Map<String,String> map);

}


定义一个网络请求的管理类,需要注意的是这里的baseUrl创建了,如果url是在其基础上的,就会进行相应的拼接,如果url是全路径,就会覆盖掉baseUrl

public class HttpManger {
/**
* @param baseUrl  基础Url
* @param url       附加Url
* @param callback  添加请求回调,这里直接使用的是Retrofit自身的回调接口
*/
public static void getMethod(String baseUrl, String url, final Callback<String> callback) {
Retrofit retrofit = new Retrofit.Builder().baseUrl(baseUrl).addConverterFactory(ScalarsConverterFactory.create()).build();

ProjectAPI projectAPI = retrofit.create(ProjectAPI.class);

Call<String> call = projectAPI.getMethod(url);
call.enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {
//调用回调
callback.onResponse(call, response);
}

@Override
public void onFailure(Call<String> call, Throwable t) {
//调用回调
callback.onFailure(call, t);
}
});
}


Post请求方式的封装,参数通过map集合的方式进行传递

public static void postMethod(String baseUrl, String url, Map<String, String> map, final Callback<String> callback) {

//指定客户端
Retrofit retrofit = new Retrofit.Builder().baseUrl(baseUrl).client(httpClient).addConverterFactory(ScalarsConverterFactory.create()).build();

ProjectAPI projectAPI = retrofit.create(ProjectAPI.class);

Call<String> call = projectAPI.postMethod(url, map);

call.enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {
callback.onResponse(call, response);
}
@Override
public void onFailure(Call<String> call, Throwable t) {
callback.onFailure(call, t);
}
});
}


方法调用-Get方式调用,这里的key大家可以替换一下

HttpManger.getMethod("http://japi.juhe.cn/", "http://japi.juhe.cn/qqevaluate/qq?key=96efc220a4196fafdfade0c9d1e897ac&qq=295424589", new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {
Toast.makeText(MainActivity.this, "--"+response.body(), Toast.LENGTH_SHORT).show();
}

@Override
public void onFailure(Call<String> call, Throwable t) {
Toast.makeText(MainActivity.this, "--"+t.getMessage(), Toast.LENGTH_SHORT).show();
}
});


POST方式调用

Map<String, String> map=new HashMap<>();
map.put("key","96efc220a4196fafdfade0c9d1e897ac");
map.put("qq","111111111");
HttpManger.postMethod(false,false,"http://japi.juhe.cn/","qqevaluate/qq",map,new Callback<String>(){
@Override
public void onResponse(Call<String> call, Response<String> response) {
Toast.makeText(MainActivity.this, "--"+response.body(), Toast.LENGTH_SHORT).show();
}

@Override
public void onFailure(Call<String> call, Throwable t) {
Toast.makeText(MainActivity.this, "--"+t.getMessage(), Toast.LENGTH_SHORT).show();
}
});


正好最近做到了Cookie的应用,在本讲解中进行一下讲解

创建一个保存Cookie的拦截器,用于获取服务器打给客户端的Cookie信息

public class SaveCookiesInterceptor implements Interceptor {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
//获取到响应
Response originalResponse = chain.proceed(chain.request());
//进行Cookie获取以及字符串的拼接,Cookie在使用的过程要
//根据具体公司来定

if (!originalResponse.headers("Set-Cookie").isEmpty()) {
//根据Set-Cookie获取出的信息
for (String header : originalResponse.headers("Set-Cookie")) {
Log.i("AAAA----","=="+header+"==");
String cookie = header.substring(0, header.indexOf(";") + 1);
stringBuilder.append(cookie);
}
}
//拼接时完成后将该Cookie保存到 SharedPreferences中
SharedPreferencesUtils.saveString(MyApplication.context,"cookie",stringBuilder.toString());
return originalResponse;
}
}


创建读取Cookie的拦截器

public class ReadCookiesInterceptor implements Interceptor {

@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request.Builder builder = chain.request().newBuilder();
String cookie = SharedPreferencesUtils.getString(MyApplication.context, "cookie", "");
//将cookie添加到请求头中
builder.addHeader("Cookie", cookie);
return chain.proceed(builder.build());
}
}


在HttpManager中指定拦截器的使用,但是并不是所有的请求都要保存cookie或者所有的请求都要读取cookie,所以我们添加一个判断

/**
*
* @param isReadCookie  是否要读取cookie
* @param isSaveCookie  是否要保存cookie
* @param baseUrl        基础Url
* @param url            要拼接的url
* @param map            参数集合
* @param callback       请求回调
*/
public static void postMethod(boolean isReadCookie, boolean isSaveCookie, String baseUrl, String url, Map<String, String> map, final Callback<String> callback) {

OkHttpClient httpClient = null;
if (isReadCookie && !isSaveCookie) {
httpClient = new OkHttpClient.Builder()
.addInterceptor(new ReadCookiesInterceptor())
.build();
Log.i("AAA","只读不写");
}
if (isSaveCookie && !isReadCookie) {
httpClient = new OkHttpClient.Builder()
.addInterceptor(new SaveCookiesInterceptor())
.build();
Log.i("AAA","只写不读");
}
if (isSaveCookie && isReadCookie) {
httpClient = new OkHttpClient.Builder()
.addInterceptor(new SaveCookiesInterceptor()).addInterceptor(new ReadCookiesInterceptor())
.build();
Log.i("AAA","又写又读");
} if (!isSaveCookie && !isReadCookie){
httpClient = new OkHttpClient.Builder()
.build();
Log.i("AAA","不写不读");
}
//指定客户端
Retrofit retrofit = new Retrofit.Builder().baseUrl(baseUrl).client(httpClient).addConverterFactory(ScalarsConverterFactory.create()).build();


好了,暂时写到这里,以上就是对Retrofit的一个简易封装,当然网上也有一些大神对Retrofit进行了封装。

参考资料:

Retrofit 使用详解http://blog.csdn.net/duanyy1990/article/details/52139294

Retrofit顶级封装 http://blog.csdn.net/gengqiquan/article/details/52329259

github引用地址 https://github.com/gengqiquan/HttpUtil
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息