Retrofit与okhttp都是出于Square公司,Retrofit对okhttp做了一层包装,把网络请求都交给了okhttp(可以参考okhttp3使用),因此只需要简单的配置,就能用Retrofit进行网络请求。
一、引入retrofit 2.0
需要在项目下的build.gradle添加retrofit 2.0.2
的引用
// retrofit 库
compile 'com.squareup.retrofit2:retrofit:2.0.2'
// 使用gson解析数据内容
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
如上图所示,引入retrofit 2.0.2
后,会在External Libraries
中看到retrofit-2.0.2
,okhttp-3.2.0
,okio-1.6.0
,这是因为retrofit 2.0.2
封装了okhttp-3.2.0
,而okhttp-3.2.0
又依赖于okio-1.6.0
,因此引入一个retrofit
库,会自动添加其依赖的其他库。
二、retrofit 2.0 基本使用
1、retrofit对象创建
Retrofit retrofit = new Retrofit.Builder()
// 设置基本url,通常是协议+IP地址+端口
.baseUrl(API_URL)
// 设置数据解析的格式,需要引入gson库
.addConverterFactory(GsonConverterFactory.create())
.build();
2、retrofit网络请求接口
retrofit将Http Api使用Java接口表示;
public interface GitHub {
@GET("/repos/{owner}/{repo}/contributors")
Call<List<Contributor>> contributors(
@Path("owner") String owner,
@Path("repo") String repo);
}
每一个Call
对象从GitHub接口里的方法获取,Call
基于Http的同步/异步方法想服务端获取请求结果。
Call<List<Contributor>> call = github.contributors("square", "retrofit");
3、动态设置url的Get方法
retrofit 2.0允许动态设置 URL,需要使用一对大括号{}将需要动态替换的URL内容括起来,对应的参数使用相同的字符串,同时使用@Path
注解表示。
如,需要请求这个地址(https://api.github.com/repos/square/retrofit/contributors)的数据,可以添加请求接口:
public interface GitHub {
@GET("/repos/{owner}/{repo}/contributors")
Call<List<Contributor>> contributors(
@Path("owner") String owner,
@Path("repo") String repo);
}
在实际调用的时候,传入正确的参数便可
Call<List<Contributor>> call = github.contributors("square", "retrofit");
这里给出完整的动态设置Url的同步调用Get方法源码;
/**
* 同步方法
*/
private void btn_synchronous_dynamically_getMethod() {
try {
new Thread(new Runnable() {
@Override
public void run() {
try {
// Create a very simple REST adapter which points the GitHub API.
Retrofit retrofit = new Retrofit.Builder()
// 设置基本url,通常是协议+IP地址+端口
.baseUrl(API_URL)
// 设置数据解析的格式,需要引入gson库
.addConverterFactory(GsonConverterFactory.create())
.build();
// Create an instance of our GitHub API interface.
GitHub github = retrofit.create(GitHub.class);
// Create a call instance for looking up Retrofit contributors.
Call<List<Contributor>> call = github.contributors("square", "retrofit");
// Fetch and print a list of the contributors to the library.
List<Contributor> contributors = call.execute().body();
final StringBuilder sb = new StringBuilder();
for (Contributor contributor : contributors) {
sb.append(contributor.getLogin() + " (" + contributor
.getContributions() + ")\n");
}
Log.i(TAG, "tht synchronous function run on thread id is " + Thread
.currentThread().getId());
Log.i(TAG, sb.toString());
runOnUiThread(new Runnable() {
@Override
public void run() {
mToast.setText(sb.toString());
mToast.show();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}
注:Android 4.0之后,不允许网络请求在主线程中使用。
异步方法通过在Call的enqueue中添加结果回调来完成。如果需要获取Http原始的Response
对象,使用Response raw = response.raw();
/**
* 异步方法
*/
private void btn_asynchronous_dynamically_getMethod() {
// Create a very simple REST adapter which points the GitHub API.
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
// Create an instance of our GitHub API interface.
GitHub github = retrofit.create(GitHub.class);
// Create a call instance for looking up Retrofit contributors.
Call<List<Contributor>> call = github.contributors("square", "retrofit");
// Fetch and print a list of the contributors to the library.
call.enqueue(new Callback<List<Contributor>>() {
@Override
public void onResponse(Call<List<Contributor>> call, Response<List<Contributor>>
response) {
try {
// get raw response
// Response raw = response.raw();
Log.i(TAG, "tht callback function run on thread id is " + Thread
.currentThread().getId());
StringBuilder sb = new StringBuilder();
List<Contributor> contributors = response.body();
for (Contributor contributor : contributors) {
sb.append(contributor.getLogin() + " (" + contributor
.getContributions() + ")\n");
}
mToast.setText(sb.toString());
mToast.show();
Log.i(TAG, sb.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onFailure(Call<List<Contributor>> call, Throwable t) {
}
});
}
4、retrofit 查询参数
4.1、一个参数查询
如果只有一个查询参数的Get/Post请求,可以使用Query
注解;
比如针对链接(http://api.k780.com:88/?app=weather.future)请求,需要设置java请求接口为:
@POST("/")
Call<WeatherList> getWeatherForAQuery(@Query("app") String queryParams);
注:参数查询不能使用@POST(“/app={param}”),然后通过@Path注解动态传递数值。
4.2、多个参数查询
如果查询参数有多个,需要使用QueryMap
注解,参数通过Map<String,String>
对象传递。当然,也可以只使用Query
注解,不过需要添加多个Query
注解才行;
public interface YourInterface {
@GET("your-url")
Call<responsebody> postcode(@Query("op") String op, @Query("postcode") String postcode);
}
下面演示对天气Url(http://api.k780.com:88/?app=weather.future&weaid=1&&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json)数据请求;
定义请求天气的Java接口,如果是用Get请求,需要将@POST
改成@GET
,需要用到的WeatherList对象,可以再文章的最后下载demo;
public interface WeatherApi {
@POST("/")
Call<WeatherList> getWeatherForQueryMap(@QueryMap Map<String,String> options);
}
注:注解括号内容不能为空,即使baseUrl写成http://api.k780.com:88/,注解也不能为 @POST(“”),否则运行出错。
最终调用方法;
private void btn_asynchronous_queryParamete_getMethod() {
try {
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://api.k780.com:88/")
.addConverterFactory(GsonConverterFactory.create()).build();
Map<String, String> options = new HashMap<String, String>();
options.put("app", "weather.future");
options.put("weaid", "1");
options.put("appkey", "10003");
options.put("sign", "b59bc3ef6191eb9f747dd4e83c99f2a4");
options.put("format", "json");
Call<WeatherList> result = retrofit.create(WeatherApi.class).getWeather2(options);
result.enqueue(new Callback<WeatherList>() {
@Override
public void onResponse(Call<WeatherList> call, Response<WeatherList> response) {
Log.i("MainActivity", new Gson().toJson(response.body()));
}
@Override
public void onFailure(Call<WeatherList> call, Throwable t) {
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
4.3、同名的多个查询参数
有些情况下通过同名的多个参数请求,比如https://api.example.com/tasks?id=123&id=124&id=125 ,由于参数数据类型是一样的,可以通过List<>
组合多个参数;
public interface TaskService {
@GET("/tasks")
Call<List<Task>> getTask(@Query("id") List<Long> taskIds);
}
5、发送json参数
当请求参数是个JSON字符串,可以使用@Body注解一个对象,Retrofit可以将一个对象转化为JSON字符串;
定义一个对象;
public class Task {
private long id;
private String text;
public Task(long id, String text) {
this.id = id;
this.text = text;
}
}
声明请求数据接口;
public interface TaskService {
@POST("/tasks")
Call<Task> createTask(@Body Task task);
}
调用方法;
Task task = new Task(1, "my task title");
Call<Task> call = taskService.createTask(task);
call.enqueue(new Callback<Task>() {});
调用createTask
方法,把task
对象的属性转化为JSON形式,对应的task
参数实际为
{
"id": 1,
"text": "my task title"
}
5、文件上传
retrofit的文件上传,需要使用@Multipart
注解;
文件上传接口定义;
public interface FileUploadService {
public static final String BASE_URL = "http://your.api/endpoint/base-url";
@Multipart
@POST("/upload")
void upload(@Part("myfile") TypedFile file,
@Part("description") String description,
Callback<String> cb);
}
定义call对象模板;
public class ServiceGenerator {
public static final String API_BASE_URL = "http://your.api-base.url";
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
public static <S> S createService(Class<S> serviceClass) {
Retrofit retrofit = builder.client(httpClient.build()).build();
return retrofit.create(serviceClass);
}
}
实际调用;
FileUploadService service = ServiceGenerator.createService(FileUploadService.class, FileUploadService.BASE_URL);
TypedFile typedFile = new TypedFile("multipart/form-data", new File("path/to/your/file"));
String description = "hello, this is description speaking";
service.upload(typedFile, description, new Callback<String>() {
@Override
public void success(String s, Response response) {
Log.e("Upload", "success");
}
@Override
public void failure(RetrofitError error) {
Log.e("Upload", "error");
}
});
TypedFile
在Retrofit
中定义,提供File
和mime type
两个参数,这里使用的mime type
值为multipart/form-data
。