本文首发于微信公众号「后厂技术官」
相关文章
Android网络编程系列
前言
Retrofit是Square公司开发的一款针对Android网络请求的框架,Retrofit2底层基于OkHttp实现的,而OkHttp现在已经得到Google官方认可,不了解OKHttp的请查看本系列的前作。
1.使用前准备
老生长谈,先配置build.gradle:
dependencies { ... compile 'com.squareup.retrofit2:retrofit:2.1.0' compile 'com.squareup.retrofit2:converter-gson:2.1.0' compile 'com.squareup.retrofit2:converter-scalars:2.1.0'//ConverterFactory的String依赖包 }
|
当然别忘了在manifest加入访问网络的权限:
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
|
这次我们访问的网站产生了变化,我们用淘宝ip库,里面有访问接口的说明:
1. 请求接口(GET):
/service/getIpInfo.php?ip=[ip地址字串]
2. 响应信息:
(json格式的)国家 、省(自治区或直辖市)、市(县)、运营商
3. 返回数据格式:
{ “code”: 0, ”data”: { “ip”: ”210.75.225.254”, ”country”: ”\u4e2d\u56fd”, ”area”: ”\u534e\u5317”, “region”: ”\u5317\u4eac\u5e02”, ”city”: ”\u5317\u4eac\u5e02”, ”county”: ”“, ”isp”: ”\u7535\u4fe1”, “country_id”: ”86”, ”area_id”: ”100000”, ”region_id”: ”110000”, ”city_id”: ”110000”, “county_id”: ”-1”, ”isp_id”: ”100017” } }
|
其中code的值的含义为,0:成功,1:失败。
2.用Retrofit异步访问网络
编写实体类
我们可以用JSON字符串转换成Java实体类(POJO)这个网站将Json转为实体类,经过修改的实体类如下:
IpModel.java:
public class IpModel { private int code; private IpData data; public void setCode(int code) { this.code = code; } public int getCode() { return this.code; } public void setData(IpData data) { this.data = data; } public IpData getData() { return this.data; } }
|
IpData.java:
public class IpData { private String country; private String country_id; private String area; private String area_id; private String region; private String region_id; private String city; private String city_id; private String county; private String county_id; private String isp; private String isp_id; private String ip; public void setCountry(String country) { this.country = country; } public String getCountry() { return this.country; } public void setCountry_id(String country_id) { this.country_id = country_id; } ... }
|
请求网络接口
public interface IpService{ @GET("getIpInfo.php") Call<IpModel> getIpMsg(@Query("ip")String ip); }
|
Retrofit提供的请求方式注解有@GET和@POST等,分别代表GET请求和POST请求,我们在这里访问的界面是“getIpInfo.php”。参数注解有@PATH和@Query等,@Query就是我们的请求的键值对的设置,在这里@Query(“ip”)代表键,“String ip”则代表值。
创建Retrofit
String url = "http://ip.taobao.com/service/"; Retrofit retrofit = new Retrofit.Builder() .baseUrl(url) .addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .build();
|
这里的baseUrl加上之前@GET(“getIpInfo.php”)定义的参数形成完整的请求地址;addConverterFactory用于指定返回的参数数据类型,这里我们支持String和Gson类型。
用Retrofit创建接口文件
IpService ipService = retrofit.create(IpService.class); Call<IpModel>call=ipService.getIpMsg(ip);
|
用retrofit创建我们之前定义的IpService接口对象,并调用该接口定义的getIpMsg方法得到Call对象。
用Call请求网络并处理回调
call.enqueue(new Callback<IpModel>() { @Override public void onResponse(Call<IpModel> call, Response<IpModel> response) { String country= response.body().getData().getCountry(); Log.i("wangshu","country"+country); Toast.makeText(getApplicationContext(),country,Toast.LENGTH_SHORT).show(); } @Override public void onFailure(Call<IpModel> call, Throwable t) { } });
|
这里是异步请求网络,回调的Callback是运行在主线程的。得到返回的Response后将返回数据的country字段用Toast显示出来。如果想同步请求网络请使用 call.execute(),如果想中断网络请求则可以使用 call.cancel()。
完整的代码如下:
public class MainActivity extends AppCompatActivity { private Button bt_request; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bt_request = (Button) findViewById(R.id.bt_request); bt_request.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { getIpInformation("59.108.54.37"); } }); } private void getIpInformation(String ip) { String url = "http://ip.taobao.com/service/"; Retrofit retrofit = new Retrofit.Builder() .baseUrl(url) .addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .build(); IpService ipService = retrofit.create(IpService.class); Call<IpModel>call=ipService.getIpMsg(ip); call.enqueue(new Callback<IpModel>() { @Override public void onResponse(Call<IpModel> call, Response<IpModel> response) { String country= response.body().getData().getCountry(); Log.i("wangshu","country"+country); Toast.makeText(getApplicationContext(),country,Toast.LENGTH_SHORT).show(); } @Override public void onFailure(Call<IpModel> call, Throwable t) { } }); }
|
3.请求参数
上文讲了Retrofit访问网络的基本方法,接下来我们来了解下Retrofit常用的请求参数。
请求方法
请求方法除了上文讲到的@GET,还有@POST、@PUT、@DELETE、@HEAD、@OPTIONS、@PATCH、@HTTP。其中@HTTP用来替换以上7个,其他的分别对应着不同的请求方法,不明白的请查看Android网络编程(一)HTTP协议原理这一篇文章。
@Query
前面的例子就用了Query用来查询参数。
public interface IpService{ @GET("getIpInfo.php") Call<IpModel> getIpMsg(@Query("ip")String ip); }
|
@QueryMap
如果Query参数比较多,那么可以通过@QueryMap方式将所有的参数集成在一个Map统一传递。
public interface BlueService { @GET("book/search") Call<BookSearchResponse> getSearchBooks(@QueryMap Map<String, String> options); }
|
@Path
@Path用来替换路径。
public interface ApiStores { @GET("adat/sk/{cityId}.html") Call<ResponseBody> getWeather(@Path("cityId") String cityId); }
|
@Body
@Body与@POST注解一起使用,提供查询主体内容,其中ApiInfo是一个bean类。
public interface ApiStores { @POST("client/shipper/getCarType") Call<ResponseBody> getCarType(@Body ApiInfo apiInfo); }
|
interface SomeService { @GET("some/endpoint") @Headers("Accept-Encoding: application/json") Call<ResponseBody> getCarType(); }
|
@Headers用来添加头部信息,上面用的是固定头部,也可以采用动态头部:
interface SomeService { @GET("some/endpoint") Call<SomeResponse> someEndpoint( @Header("Location") String location); }
|
@Multipart
@Multipart用来上传文件
public interface FileUploadService { @Multipart @POST("upload") Call<ResponseBody> upload(@Part("description") RequestBody description, @Part MultipartBody.Part file); }
|
github源码下载
参考资料
Retrofit 2.0文件上传
RxJava 与 Retrofit 结合的最佳实践
Retrofit2使用初探
android 介绍Retrofit的简单使用
Retrofit框架使用笔记
Retrofit 解析 JSON 数据
用 Retrofit 2 简化 HTTP 请求
Android Retrofit 2.0使用