Retrofit简介:
Retrofit是Square公司开发的一款针对Android网络请求的框架,Retrofit2底层基于OkHttp实现的,Okhttp现在已经得到Google官方认可,大量的app都采用OkHttp做网络请求
1.要使用Retrofit首先得添加gradle依赖
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
2.新建一个Retrofit对象
mRetrofit = new Retrofit.Builder()
.baseUrl("http://192.168.0.102/")
.client(configClient())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
需要注意的是baseUrl必须以”/”结尾
3.新建一个Interface,需要请求的接口服务类
public interface Api {
@GET("index.php?c=User&m=getUser")
Call> getUser();
}
在我们定义请求的接口时,会传入具体的接口的地址(Endpoint):
@GET("index.php?c=User&m=getUser")
Call> getUser();
Retrofit会帮我们完成拼接,最后的URL是:
http://192.168.0.102/index.php?c=User&m=getUser
Endpoint可以为完整的URL:
Base URL: http://example.com/
Endpoint: https://github.com/square/retrofit/
Result: https://github.com/square/retrofit/
当我们需要请求不同服务器上的API时,这就非常有用了。
@GET
Call> getUser2(@Url String url);
Call> call=userClient.getUser2("http://www.jiangxu.online/index.php?c=User&m=getUser");
Retrofit中一些参数注解:
@Path:所有在网址中的参数(URL的问号前面),如:
http://102.10.10.132/api/Accounts/{accountId}
@Query:URL问号后面的参数,如:
http://102.10.10.132/api/Comments?access_token={access_token}
@QueryMap:相当于多个@Query
@Field:用于POST请求,提交单个数据
@Body:相当于多个@Field,以对象的形式提交
@Path和@Query的区别;
example:www.app.net/api/searchtypes/862189/filters?Type=6&SearchText=School
@GET("/api/searchtypes/{Id}/filters")
void getFilterList(@Path("Id") long customerId,
@Query("Type") String responseType,
@Query("SearchText") String searchText,
CallbackfilterResponse);
url拼接:www.app.net/api/searchtypes/{Path}/filters?Type={Query}&SearchText={Query}
Get查询参数
查询参数是一种很常见的客户端往服务端传递数据的方式,比如我们需要传一个id给服务端,那么URL可能是这样的:
https://api.example.com/tasks?id=123
Retrofit 定义实现查询参数:
public interface TaskService {
@GET("/tasks")
Call getTask(@Query("id") long taskId);
}
方法getTask需要传入taskId,这个参数会被映射到@Query(“id”)中的id中,最后的URL会变成这样:
/tasks?id=
有时我们需要对于一个id参数传入多个值,比如这样:
https://api.example.com/tasks?id=123&id=124&id=125
对于这样的需求,Retrofit 通过传入一个List来实现:
public interface TaskService {
@GET("/tasks")
Call> getTask(@Query("id") List taskIds);
}
这样,拼接后的URL就是我们需要的那样。
有时,我们在给服务端传递数据时,有些参数是可选的,比如下面的URL:
https://your.api.com/tasks?sort=value-of-order-parameter
sort参数是可选的,有些情况下可能不需要传入。
接口的定义:
public interface TaskService {
@GET("/tasks")
Call> getTasks(@Query("sort") String order);
}
那么,在我们不想添加排序控制的时候,我们可以传入null,Retrofit 会忽略值为null的参数。
service.getTasks(null);
需要注意的是,可忽略参数的参数类型不能是int, float, long这些基本类型,应该用Integer, Float, Long来代替。
Post 提交参数
Retrofit Post方式提交表单形式的参数需要添加标记@FormUrlEncoded,通过@Field注释添加键值对。
接口定义:
public interface UserClient {
@FormUrlEncoded
@POST("/index.php?c=User&m=login")
Call> login(@Field("phone") String phone, @Field("password") String password);
}
客户端调用:
private void login() {
UserClient userClient = ServiceGenerator.createService(UserClient.class);
Call> call = userClient.login("13695378745","123456");
call.enqueue(new Callback>() {
});
}
Post 提交JSON数据
有时提交的数据量比较大时,用键值对的方式提交参数不太方便,Retrofit可以通过@Body注释,直接传递一个对象给请求主体,Retrofit通过JSON转化器,把对象映射成JSON数据。
接口定义:
public interface TaskService {
@POST("/tasks")
Call createTask(@Body Task task);
}
传递实体需要有Model:
public class Task {
private long id;
private String text;
public Task() {}
public Task(long id, String text) {
this.id = id;
this.text = text;
}
}
客户端调用:
Task task = new Task(1, "my task title");
Call call = taskService.createTask(task);
call.enqueue(new Callback() {});
这样,服务端得到的是JOSN数据:
{
"id": 1,
"text": "my task title"
}
文件下载
接口定义:
@Streaming
@GET
Call downloadFile(@Url String fileUrl);
在下载的时候,是在子线程中工作运行的,有时需要显示下载的进度,同时支持多个下载并发进行,这样需要封装一下,使用起来方便:
public class DownFileManager {
private final static String TAG = "DownFileManager";
private static DownFileManager sDownFileManager;
private CallBack mCallBack;
private final Handler mHandler = new Handler(Looper.getMainLooper());
private ExecutorService executorService;
public interface CallBack {
void onSuccess(String path);
void inProgress(int progress);
void onFail();
}
public static DownFileManager getInstance() {
if (sDownFileManager == null) {
sDownFileManager = new DownFileManager();
}
return sDownFileManager;
}
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new SynchronousQueue(), Util.threadFactory("DownFileManager", false));
}
return executorService;
}
public void download(final String path, final String filePath, CallBack callBack) {
mCallBack = callBack;
executorService();
executorService.submit(new Runnable() {
boolean isSuccess;
@Override
public void run() {
DownloadService service = ServiceGenerator.createService(DownloadService.class);
Call call = service.downloadFile(path);
try {
isSuccess = writeResponseBodyToDisk(filePath, call.execute().body());
} catch (Exception e) {
e.printStackTrace();
}
mHandler.post(new Runnable() {
@Override
public void run() {
if (isSuccess) {
mCallBack.onSuccess(filePath);
} else {
mCallBack.onFail();
}
}
});
}
});
}
private boolean writeResponseBodyToDisk(String path, ResponseBody body) {
try {
File futureStudioIconFile = new File(path);
InputStream inputStream = null;
OutputStream outputStream = null;
try {
byte[] fileReader = new byte[4096];
long fileSize = body.contentLength();
long fileSizeDownloaded = 0;
inputStream = body.byteStream();
outputStream = new FileOutputStream(futureStudioIconFile);
int oldProgress = 0;
while (true) {
int read = inputStream.read(fileReader);
if (read == -1) {
break;
}
outputStream.write(fileReader, 0, read);
fileSizeDownloaded += read;
final int progress = (int) ((fileSizeDownloaded * 1.0 / fileSize) * 100);
if (oldProgress != progress) {
mHandler.post(new Runnable() {
@Override
public void run() {
mCallBack.inProgress(progress);
}
});
}
oldProgress = progress;
}
outputStream.flush();
return true;
} catch (IOException e) {
return false;
} finally {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
}
} catch (IOException e) {
return false;
}
}
}
使用:
DownFileManager.getInstance().download(downloadUrl, filePath, new DownFileManager.CallBack() {
@Override
public void onSuccess(String path) {
//下载文件的路径
}
@Override
public void inProgress(int progress) {
//下载的进度
Trace.i("DownFileManager","progress ="+progress);
}
@Override
public void onFail() {
}
});
文件上传
Retrofit 支持 Multipart 请求,所以我们可以用它来实现文件上传,对于要实现文件上传的接口,需要添加@Multipart注释。
接口定义:
public interface FileUploadService {
@Multipart
@POST("index.php?c=Upload&m=doUpload")
Call upload(
@Part("file\"; filename=\"image.png\" ") RequestBody file,
@Part("description") RequestBody description);
}
对于要上传的文件,我们需要把它包装成RequestBody 对象:
private void uploadFile( File file) {
FileUploadService service =
ServiceGenerator.createService(FileUploadService.class);
String descriptionString = "hello, this is description speaking";
RequestBody description =
RequestBody.create(MediaType.parse("multipart/form-data"), descriptionString);
RequestBody requestBody =
RequestBody.create(MediaType.parse("multipart/form-data"), file);
Call call = service.upload(requestBody, description);
call.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
Log.v("Upload", "success");
}
@Override
public void onFailure(Call call, Throwable t) {
Log.e("Upload", t.getMessage());
}
});
}
同步请求和异步请求
同步的请求会在同一个线程中执行,在Android中必须另开线程,否则在主线程中执行会抛出异常。
同步和异步请求的接口都是一样的,只是调用的时候会不一样:
public interface TaskService {
@GET("/tasks")
Call> getTasks();
}
同步请求调用:
TaskService taskService = ServiceGenerator.createService(TaskService.class);
Call> call = taskService.getTasks();
List> tasks = call.execute().body();
异步请求调用:
TaskService taskService = ServiceGenerator.createService(TaskService.class);
Call> call = taskService.getTasks();
call.enqueue(new Callback>() {
@Override
public void onResponse(Call> call, Response> response) {
if (response.isSuccess()) {
// tasks available
} else {
// error response, no access to resource?
}
}
@Override
public void onFailure(Call> call, Throwable t) {
// something went completely south (like no internet connection)
Log.d("Error", t.getMessage());
}
}
异步请求实现了一个CallBack,包含了两个回调方法:onResponse和 onFailure,在onResponse中我们可以拿到我们需要的实体数据,在onFailure中,可以拿到错误的Log。
原文地址:http://blog.csdn.net/jiangxuqaz/article/details/50759239
部分内容,也根据自己的理解添加或者修改
Demo地址:
http://download.csdn.net/detail/jiangxuqaz/9452369