Retrofit 2.1入门
几种网络框架的比较1、volley一个简单的http异步请求库,但不支持同步,不能post大数据(上传文件时有问题);2、android-async-http和volley一样,是异步的请求库,只不过volley使用的是httpUrlConnection,而它使用的是HttpClient。这个库已经不再适合Android;3、okhttp基于httpUrlConnection,支持同步和异步,但需要自己再封装下;4、retrofit;对 okhttp再次封装,在项目中可以直接使用。在项目中引用retrofit,分为几个部分- module对象- Converter的实现类- Service类(定义网址中不固定的部分)- OkHttpClient和Retrofit
//1.创建Retrofit对象
//2.创建访问API的请求
//3.发送请求
//4.处理结果
1、配置
compile 'com.squareup.okhttp3:okhttp-urlconnection:3.4.0-RC1'compile 'com.google.code.gson:gson:2.7'compile 'com.squareup.retrofit2:retrofit:2.1.0'compile 'com.squareup.retrofit2:converter-gson:2.1.0'
GET方式
public interface SimpleGET { @GET("/") //表明是GET方式. "/"会拼接在setEndpoint(url)中url(主机地址)的后面. Call<ResponseBody> getResponse(); //可以简单的理解为网络访问完把Response转换为一个对象.这里没有转换,还是Response.}
public static void simpleGET(){ String url="http://tieba.baidu.com"; Retrofit retrofit=new Retrofit.Builder() .baseUrl(url) .build(); SimpleGET create=retrofit.create(SimpleGET.class); final Call<ResponseBody> call=create.getResponse(); try { /*错误 的调用 Response response=create.getResponse().execute(); System.out.print(response.body().toString());*/ Response<ResponseBody> bodyResponse = call.execute(); String body = bodyResponse.body().string();//获取返回体的字符串 System.out.print(body); } catch (IOException e) { e.printStackTrace(); }}
POST方式
public interface SimplePOST { @POST("/androdi") Call<ResponseBody> getResponse();}
PATH 路径path是可以动态替换的.static class Contributor {
//一个pojo类(Plain Ordinary Java Object)简单的Java对象-->相比javaBean更简单. GsonConverter默认的转换器
String login;
int contributions;
}
interface GitHub {
@GET("/repos/{owner}/{repo}/contributors")
Call<List<Contributor>> contributors(@Path("owner") String owner, @Path("repo") String repo);
}
public static void path_GitHub(){ String url="https://api.github.com"; Retrofit retrofit=new Retrofit.Builder() .baseUrl(url) .addConverterFactory(GsonConverterFactory.create()) .build(); GitHub create=retrofit.create(GitHub.class); /** * 访问这个地址返回的是一个JsonArray,JsonArray的每一个元素都有login * 和contributions这2个key和其对应的value.提取出来封装进POJO对象中. */ Call<List<Contributor>> call=create.contributors("square", "retrofit"); try { Response<List<Contributor>> response=call.execute(); List<Contributor>list=response.body(); for (Contributor c:list) { System.out.println(c.toString()); } } catch (IOException e) { e.printStackTrace(); }}
自定义的Converter(StringConverter)Response可以获得输入流,我们可以把它转换成任何想要的格式.
自定义的StringConverter转换器
public class StringConverter implements Converter<ResponseBody,String>{ static final StringConverter.Factory FACTORY=new StringConverter.Factory(){ @Override public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { /*if (type==StringConverter.class)return new StringConverter(); else return null;*/ return new StringConverter(); } }; @Override public String convert(ResponseBody value) throws IOException { //values.string 把服务器上请求的数据,转换成string格式// String str=convertStream2String(value.byteStream()); return value.string(); } private String convertStream2String(InputStream in) throws IOException { //inputStream转换为String 要进行gbk或者utf-8转码,否则乱码 BufferedReader reader = new BufferedReader(new InputStreamReader(in, "GBK"));// BufferedReader reader=new BufferedReader(new InputStreamReader(in)); StringBuilder sb=new StringBuilder(); String line=null; while((line=reader.readLine())!=null){ sb.append(line); sb.append("\n"); } return sb.toString(); }}
public interface StringClient { //方法的返回值是String,需要StringConverter转换器Converter把Response转换为String. @GET("/") Call<String> getString();}
public static void Get_String(){ String url="http://tieba.baidu.com"; Retrofit retrofit=new Retrofit.Builder() .baseUrl(url) .addConverterFactory(StringConverter.FACTORY) .build(); final StringClient strClient=retrofit.create(StringClient.class); Call<String>call=strClient.getString(); try { Response<String> str=call.execute(); System.out.print(str.body()); } catch (IOException e) { e.printStackTrace(); }}
Query注解public interface QueryGET { @GET("/sheet") Call<String> getString(@Query("name") String name, @Query("age")int age, @QueryMap(encoded=true) Map<String, String> filters );}
public static void QueryGET(){ String url="http://tieba.baidu.com"; Map<String, String> map=new HashMap<>(); map.put("gender","male"); map.put("address","sz"); Retrofit retrofit=new Retrofit.Builder() .baseUrl(url) .addConverterFactory(StringConverter.FACTORY) .build(); QueryGET queryGET=retrofit.create(QueryGET.class); Call<String> call=queryGET.getString("laiqurufeng", 22, map); try { Response<String>body=call.execute(); System.out.print(body.body()); } catch (IOException e) { e.printStackTrace(); }}
query 访问的参数会添加到路径(path)的后面.
实际访问的url是 (模拟的访问)
encoded =true表示对url的query进行url编码,同理还有encodeValues. 这2个的值默认都是true的
如果上面的代码换成 map.put("性别","男") ,然后更改@QueryMap(encoded =false )
那么实际访问的url变成了 (可以看到key没有进行url编码,value进行了url编码).
Header注解
header分为key和value都固定,静态Header注解方法 和 动态Header注解方法
注意header不会相互覆盖.
静态Header
interface FixedHeader{
@Headers({ //静态Header
"Accept: application/vnd.github.v3.full+json",
"User-Agent: Retrofit-Sample-App"
})
@GET("/")
Call<ResponseBody> getResponse();
}
动态Header
interface DynamicHeader{
@Headers("Cache-Control: max-age=640000") //动态Header
@GET("/")
Call<ResponseBody> getResponse(
@Header("header1")String header1,
@Header("header2")String header2);
//动态Header,其value值可以在调用这个方法时动态传入.
}
例子:
public class PhoneResult { /** * errNum : 0 * retMsg : success * retData : {"phone":"15210011578","prefix":"1521001","supplier":"移动","province":"北京","city":"北京","suit":"152卡"} */ public int errNum; public String retMsg; /** * phone : 15210011578 * prefix : 1521001 * supplier : 移动 * province : 北京 * city : 北京 * suit : 152卡 */ public RetDataEntity retData; public static class RetDataEntity { public String phone; public String prefix; public String supplier; public String province; public String city; public String suit; @Override public String toString() { return "RetDataEntity{" + "phone='" + phone + '\'' + ", prefix='" + prefix + '\'' + ", supplier='" + supplier + '\'' + ", province='" + province + '\'' + ", city='" + city + '\'' + ", suit='" + suit + '\'' + '}'; } }}
Service:
动态Header
public interface PhoneService { @GET("/apistore/mobilenumber/mobilenumber") Call<PhoneResult> getResult( @Header("apikey")String apikey, @Query("phone")String phone );}
静态Header
public interface PhoneServiceDynamic { @Headers("apikey:8e13586b86e4b7f3758ba3bd6c9c9135") @GET("/apistore/mobilenumber/mobilenumber") Call<PhoneResult> getResult( @Query("phone")String phone );}
调用
public static void phone_Query(String phone){ final String BASE_URL="http://apis.baidu.com"; final String API_KEY="8e13586b86e4b7f3758ba3bd6c9c9135"; //1.创建Retrofit对象 Retrofit retrofit=new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .build(); //2.创建访问API的请求 PhoneService service=retrofit.create(PhoneService.class); Call<PhoneResult>call=service.getResult(API_KEY,phone); //3.发送请求 try { Response<PhoneResult>response=call.execute(); //4.处理结果 if (response.isSuccessful()) { PhoneResult result=response.body(); if (result!=null) { PhoneResult.RetDataEntity entity = result.getRetData(); System.out.print(entity.toString()); } } } catch (IOException e) { e.printStackTrace(); } /*异步调用
call.enqueue(new Callback<PhoneResult>() { @Override public void onResponse(Call<PhoneResult> call, Response<PhoneResult> response) { //4.处理结果 if (response.isSuccessful()) { PhoneResult result=response.body(); if (result!=null) { PhoneResult.RetDataEntity entity = result.getRetData(); System.out.print(entity.toString()); } } } @Override public void onFailure(Call<PhoneResult> call, Throwable t) { } });*/}
上传文件
public interface UploadServer { @Headers({ //静态Header "User-Agent: androidphone" }) @Multipart @POST("/service.php?mod=avatar&type=big") // upload is a post field // without filename it didn't work! I use a constant name because server doesn't save file on original name //@Part("filename=\"1\" ") RequestBody //以表单的形式上传图片 Call<JsonObject> uploadImageM(@Part("file\";filename=\"1") RequestBody file);// Call<ResponseBody> uploadImage(@Part("file\"; filename=\"image.png\"") RequestBody file); /** * 以二进制流的形式上传 图片 * @param file * @return */ @Headers({ //静态Header "User-Agent:androidphone" }) @POST("/service.php?mod=avatar&type=big") Call<ResponseBody> uploadImage(@Body RequestBody file);}
调用
public static void upload(String fpath) { // path to file like /mnt/sdcard/myfile.txt String baseurl="http://dev.123go.net.cn"; File file = new File(fpath); // please check you mime type, i'm uploading only images RequestBody requestBody = RequestBody.create(MediaType.parse("image/*"), file); /*RequestBody rbody=new MultipartBody.Builder() .addPart(requestBody).build(); RequestBody requestFile = RequestBody.create(MediaType.parse("image/jpg"), file); MultipartBody.Part body = MultipartBody.Part.createFormData("image", file.getName(), requestFile); */ Retrofit retrofit=new Retrofit.Builder() .baseUrl(baseurl) .addConverterFactory(GsonConverterFactory.create()) .client(getOkhttpClient()) .build(); // 添加描述 /*String descriptionString = "hello, 这是文件描述"; RequestBody description = RequestBody.create( MediaType.parse("multipart/form-data"), descriptionString);*/ UploadServer server=retrofit.create(UploadServer.class); Call<ResponseBody> call = server.uploadImage(requestBody); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { ResponseBody jsonObject=response.body(); System.out.print(jsonObject.toString()); } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { } });}
private static OkHttpClient getOkhttpClient(){ final String cookie="your cookie"; OkHttpClient httpClient = new OkHttpClient.Builder() .addInterceptor(new Interceptor() { @Override public okhttp3.Response intercept(Chain chain) throws IOException { Request request = chain.request() .newBuilder()// .addHeader("Content-Type", " application/x-www-form-urlencoded; charset=UTF-8")// .addHeader("Accept-Encoding", "gzip, deflate")// .addHeader("Connection", "keep-alive")// .addHeader("Accept", "***") .addHeader("Cookie", cookie) .build(); return chain.proceed(request); } }) .build();
return httpClient; }