为什么要写这篇博客呢?
- 由于主要从事系统应用的开发,很少涉及到网络相关的开发;
- 最近要解决应用OTA问题,参考其他项目的代码,里面使用了Retrofit 库;
- 平时看博客时,发现很多人都在使用Retrofit +RxJava+MVP/MVVM的模式进行开发网络应用。
正所谓天时地利人和,是时候学习下Retrofit 了。
Retrofit
A type-safe HTTP client for Android and Java.
学习一个库的使用方法,不是一开始学习它的原理,而是从最简单的API开始,一步步搭建自己的应用,当熟练到一定程度,或者现有的功能无法满足自己的需求时,才可进行深入的了解。
本文将根据Retrofit的官方文档,一步步介绍它在Android中的使用方法。
JSON数据
本文将利用Retrofit请求天气预报的Json数据为主线。天气预报Json数据的HTTP请求地址为:1
http://www.weather.com.cn/data/sk/101110101.html
其中101110101
为城市代码,虽然这个API可以请求到数据,但是结果却不是真实的天气状况-_-||。更多天气预报接口API的介绍参见中国天气网-天气预报接口api。
如果网络可达,且接口有效,那么可以得到如下数据:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17{
"weatherinfo": {
"city": "西安",
"cityid": "101110101",
"temp": "23.3",
"WD": "西南风",
"WS": "小于3级",
"SD": "52%",
"AP": "962.7hPa",
"njd": "暂无实况",
"WSE": "<3",
"time": "18:00",
"sm": "1.2",
"isRadar": "1",
"Radar": "JC_RADAR_AZ9290_JB"
}
}
那么根据Json数据定义一个Weather
类:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public class Weather {
public WeatherInfo weatherinfo;
public static class WeatherInfo {
public String city;
public String cityid;
public String temp;
public String WD;
public String WS;
public String SD;
public String AP;
public String njd;
public String WSE;
public String time;
public String sm;
public String isRadar;
public String Radar;
}
}
使用Retrofit库
添加依赖
首先需要在build.gradle(Module)文件中添加依赖:1
2implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
顾名思义,第一个是Retrofit库本身;第二个Retrofit封装的gson库。
WeatherService
WeatherService
类用于封装各种HTTP请求,不过本文中只有一个:1
2
3
4public interface WeatherService {
@GET("data/sk/{cityId}.html")
Call<Weather> getCityWeather(@Path("cityId") String cityId);
}
其中
@GET
表示HTTP的GET
方法;data/sk/{cityId}.html
是http://www.weather.com.cn/data/sk/101110101.html
去除Base Url后剩余的部分;cityId
表示城市代码,通过方法的参数传入;@Path
可以理解为参数将插入url的路径中。
WeatherRepository
WeatherRepository
类用于封装上一步WeatherService
的创建过程:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24public class WeatherRepository {
private static final String BASE_URL = "http://www.weather.com.cn/";
private WeatherService mWeatherService;
private WeatherRepository() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
mWeatherService = retrofit.create(WeatherService.class);
}
private static class SingletonHolder {
private static final WeatherRepository INSTANCE = new WeatherRepository();
}
public static WeatherRepository getInstance() {
return SingletonHolder.INSTANCE;
}
public WeatherService getWeatherService() {
return mWeatherService;
}
}
其中最主要的是mWeatherService
的创建过程(WeatherRepository
的构造函数),一是传入Base Url,二是添加Json数据转换器。
数据请求
最后一步就是请求数据。现在只要在合适的地方调用如下方法:1
2
3
4
5
6
7
8
9
10
11
12
13
14WeatherRepository.getInstance()
.getWeatherService()
.getCityWeather("101110101")
.enqueue(new Callback<Weather>() {
@Override
public void onResponse(@NonNull Call<Weather> call, @NonNull Response<Weather> response) {
Log.d(TAG, new Gson().toJson(response.body()));
}
@Override
public void onFailure(@NonNull Call<Weather> call, @NonNull Throwable t) {
t.printStackTrace();
}
});
该方法为异步调用,所以可以放在UI线程中。如果请求成功可以看到类似下面的log输出:1
2019-01-20 16:15:41.700 5889-5889/com.ihuntto.retrofitweather D/MainActivity: {"weatherinfo":{"AP":"962.7hPa","Radar":"JC_RADAR_AZ9290_JB","SD":"52%","WD":"西南风","WS":"小于3级","WSE":"\u003c3","city":"西安","cityid":"101110101","isRadar":"1","njd":"暂无实况","sm":"1.2","temp":"23.3","time":"18:00"}}
如果请求失败可以看到类似下面的log输出:1
2
32019-01-20 16:30:50.204 6643-6643/com.ihuntto.retrofitweather W/System.err: java.net.UnknownHostException: Unable to resolve host "www.weather.com.cn": No address associated with hostname
2019-01-20 16:30:50.208 6643-6643/com.ihuntto.retrofitweather W/System.err: at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:141)
2019-01-20 16:30:50.209 6643-6643/com.ihuntto.retrofitweather W/System.err: at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:90)
完整的代码在GitHub项目:RetrofitWeather
总结与想法
本文对Retrofit的介绍并不是十分全面,只适用于初学阶段,许多地方并未深入介绍,如@POST
方法、@Headers
添加静态HTTP头、自定义OkHttp,网上有很多详细介绍的文章,如网络加载框架 - Retrofit。有时候写博客的目的,并不是为了传播知识,而是为了巩固自己使用过的知识,加深自己的理解。
参考文档
[1] Retrofit
[2] 中国天气网-天气预报接口api
[3] 网络加载框架 - Retrofit