Q:What is Retrofit ?
A:Type-safe HTTP client for Android and Java by Square, Inc.
Retrofit 官网:http://square.github.io/retrofit/
Retrofit GitHub 项目地址:https://github.com/square/retrofit
在使用 Retrofit 之前,我们需要一些前期的准备:
① API 接口测试工具:Chrome 浏览器推荐使用 Postman,Firefox 浏览器推荐使用 RESTClient 。
② 将 API 返回的数据自动生成 Java 类对象:在 Android Studio 里面安装插件 GsonFormat 。
前期工作准备就绪,开始 Retrofit 之旅!
本文基于 Retrofit 2 进行代码编写。
学习任何东西都会有官网给提供的参考示例,Retrofit 也给提供了一套示例代码:
https://github.com/square/retrofit/tree/master/samples
本文你将学到:
① 使用Retrofit
网络请求
② 使用Retrofit
下载文件
③ 使用Rxjava
+Retrofit
网络请求
一、入门篇
本示例参考官方提供的 SimpleService 进行修改和编写:
https://github.com/square/retrofit/blob/master/samples/src/main/java/com/example/retrofit/SimpleService.java
示例 GIF:
Loading to Content.gif
代码部分:
① 在 Gradle 里面添加依赖库
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
② 申请网络权限
<uses-permission android:name="android.permission.INTERNET" />
③ API 接口
使用 GitHub 提供的 API 接口,因为是做 Retrofit 的演示,所以就以 Retrofit 的接口为例
https://api.github.com/repos/square/retrofit/contributors
然我们来获取一下都有哪些大神对 Retrofit 做出了贡献吧。
④ 使用插件 GsonFormat,自动创建 Java 类对象
public class Contributor {
/**
* login : JakeWharton
* avatar_url : https://avatars0.githubusercontent.com/u/66577?v=4
* html_url : https://github.com/JakeWharton
*/
private String login; // 人名
private String avatar_url; // 头像的 Url 地址
private String html_url; // 个人 GitHub 主页地址
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getAvatar_url() {
return avatar_url;
}
public void setAvatar_url(String avatar_url) {
this.avatar_url = avatar_url;
}
public String getHtml_url() {
return html_url;
}
public void setHtml_url(String html_url) {
this.html_url = html_url;
}
}
⑤ 创建 API 接口(GitHub 提供的是 GET 请求)
public interface MainService {
@GET("/repos/square/retrofit/contributors")
Call<List<Contributor>> getCall();
}
⑥ 我们从服务器上拿到的是一组 List 数据,所以要将 List 数据通过 RecyclerView 显示在 UI 上(RecyclerView 这部分不属于本示例的范畴内,默认大家都会用。)
⑦ 创建 Retrofit 实例
private void initData() {
// 创建一个非常简单的REST适配器,它指向 GitHub 的 API
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
// 创建一个我们的 GitHub API 接口的实例。
MainService service = retrofit.create(MainService.class);
// 创建一个调用实例来查找都有哪些大神对 Retrofit 做出了贡献。
Call<List<Contributor>> call = service.getCall();
Log.d(TAG, "main: " + call);
call.enqueue(new Callback<List<Contributor>>() {
@Override
public void onResponse(Call<List<Contributor>> call, Response<List<Contributor>> response) {
if (response.isSuccessful()) {
Log.d(TAG, "onResponse: " + "isSuccessful");
list = response.body();
Log.d(TAG, "onResponse: " + "list" + list);
if (list != null && list.size() > 0) {
mAdapter.setData(list);
}
}
}
@Override
public void onFailure(Call<List<Contributor>> call, Throwable t) {
}
});
}
不同于官方示例的是:我使用异步加载,而官方示例使用的是同步加载。这里也推荐使用异步加载,不要在主线程里面执行网络请求。
⑧ 将得到的 List 数据使用 RecyclerView 显示在 UI 上
- 在 Gradle 里面添加依赖库
// RecyclerView
implementation 'com.android.support:recyclerview-v7:27.0.2'
// Glide
implementation 'com.github.bumptech.glide:glide:4.3.1'
annotationProcessor 'com.github.bumptech.glide:compiler:4.3.1'
- 绑定控件,并显示在 UI 上
@Override
public void onBindViewHolder(final MainAdapter.MainViewHolder holder, int position) {
Contributor contributor = mList.get(position);
final String login = contributor.getLogin();
String htmlUrl = contributor.getHtml_url();
String avatarUrl = contributor.getAvatar_url();
Log.d(TAG, "onBindViewHolder: " + login);
Log.d(TAG, "onBindViewHolder: " + htmlUrl);
Log.d(TAG, "onBindViewHolder: " + avatarUrl);
holder.tvName.setText(login);
holder.tvUrl.setText(htmlUrl);
Glide.with(holder.ivAvatar.getContext()).load(avatarUrl).into(holder.ivAvatar);
}
以上就是入门篇的内容。
示例项目已上传至 GitHub ,下载地址:
https://github.com/cnwutianhao/Retrofit2/tree/master/app-Simple
二、进阶篇
下载 (将服务器的数据下载到本地)
参考文章:
https://futurestud.io/tutorials/retrofit-2-how-to-download-files-from-server
还是以 GitHub 上面的 api 为例:
https://api.github.com/repos/cnwutianhao/Retrofit2/contributors
根据上面的 url 地址,我们可以得到 Json 数据:
[
{
"login": "cnwutianhao",
"id": 13990136,
"avatar_url": "https://avatars1.githubusercontent.com/u/13990136?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/cnwutianhao",
"html_url": "https://github.com/cnwutianhao",
"followers_url": "https://api.github.com/users/cnwutianhao/followers",
"following_url": "https://api.github.com/users/cnwutianhao/following{/other_user}",
"gists_url": "https://api.github.com/users/cnwutianhao/gists{/gist_id}",
"starred_url": "https://api.github.com/users/cnwutianhao/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/cnwutianhao/subscriptions",
"organizations_url": "https://api.github.com/users/cnwutianhao/orgs",
"repos_url": "https://api.github.com/users/cnwutianhao/repos",
"events_url": "https://api.github.com/users/cnwutianhao/events{/privacy}",
"received_events_url": "https://api.github.com/users/cnwutianhao/received_events",
"type": "User",
"site_admin": false,
"contributions": 3
}
]
我们下载里面的图片,作为示例演示:
"avatar_url": "https://avatars1.githubusercontent.com/u/13990136?v=4",
代码部分:
① 创建 Base Api
public class MainApi {
public static final String BASE_API = "https://avatars1.githubusercontent.com/";
}
② 创建 Api 接口
public interface MainService {
// 将 ResponseBody 作为了返回类型。Retrofit 会试图解析并转换它,所以你不能使用任何其他返回类型,
// 否则当你下载文件的时候,是毫无意义的。
// 防止大文件,使用 @Streaming
@Streaming
@GET("u/13990136?v=4")
Call<ResponseBody> downloadFileWithFixedUrl();
}
注意:这里面一定要使用 ResponseBody ,使用其他的 Bean 下载也就没有意义了。
③ 创建 Retrofit 实例
private void initData() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(MainApi.BASE_API)
.addConverterFactory(GsonConverterFactory.create())
.build();
MainService service = retrofit.create(MainService.class);
Call<ResponseBody> call = service.downloadFileWithFixedUrl();
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, final Response<ResponseBody> response) {
if (response.isSuccessful()) {
Log.d(TAG, "onResponse: Server contacted and has file");
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
boolean writtenToDisk = writeResponseBodyToDisk(response.body());
Log.d(TAG, "onResponse: file download was a success? " + writtenToDisk);
return null;
}
}.execute();
} else {
Log.d(TAG, "onResponse: Server contact failed");
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d(TAG, "onFailure: ");
}
});
}
④ 创建方法,判断文件是否已经下载到本地
private boolean writeResponseBodyToDisk(ResponseBody body) {
try {
File sampleFile = new File(
getExternalFilesDir(null) + File.separator + "icon.png");
Log.d(TAG, "FutureStudioIconFile路径: " + sampleFile);
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(sampleFile);
while (true) {
int read = inputStream.read(fileReader);
if (read == -1) {
break;
}
outputStream.write(fileReader, 0, read);
fileSizeDownloaded += read;
Log.d(TAG, "file download: " + fileSizeDownloaded + " of " + fileSize);
}
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;
}
}
运行代码,查看 Log 日志:
onResponse: Server contacted and has file
FutureStudioIconFile路径: /storage/emulated/0/Android/data/com.tnnowu.retrofit2sample/files/icon.png
file download: 1903 of 26033
file download: 4662 of 26033
file download: 7421 of 26033
file download: 10180 of 26033
file download: 12939 of 26033
file download: 15528 of 26033
file download: 18287 of 26033
file download: 21046 of 26033
file download: 23805 of 26033
file download: 26033 of 26033
onResponse: file download was a success? true
我们可以清晰地看到服务器上的文件被下载到本地,路径是:
/storage/emulated/0/Android/data/com.tnnowu.retrofit2sample/files/
示例项目已上传至 GitHub ,下载地址:
https://github.com/cnwutianhao/Retrofit2/tree/master/app-Download
RxJava 和 Retrofit 结合使用
RxJava
是异步加载框架,Retroft
进行网络请求的时候也需要进行异步加载,那么这两个结合使用是非常完美的一件事。
导入必要的库:
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
implementation 'io.reactivex.rxjava2:rxjava:2.1.9'
① 根据api
中的参数,设置getter
和setter
public class GitHubBean {
private String login;
private String avatar_url;
private String html_url;
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getAvatar_url() {
return avatar_url;
}
public void setAvatar_url(String avatar_url) {
this.avatar_url = avatar_url;
}
public String getHtml_url() {
return html_url;
}
public void setHtml_url(String html_url) {
this.html_url = html_url;
}
}
② 创建API
接口
public interface GitHubService {
// Contributors
@GET("/repos/square/retrofit/contributors")
Observable<List<GitHubBean>> getContributors();
}
③ 创建Retrofit
实例
public class RetrofitService {
private static final String BASE_URL = "https://api.github.com";
public GitHubService getService() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
return retrofit.create(GitHubService.class);
}
}
④ RxJava
结合Retrofit
进行网络请求
private GitHubService mService = new RetrofitService().getService();
Observable<List<GitHubBean>> observable = mService.getContributors();
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<List<GitHubBean>>() {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "onSubscribe: ");
}
@Override
public void onNext(List<GitHubBean> gitHubBeans) {
Log.d(TAG, "onNext: ");
Log.d(TAG, "onNext: " + gitHubBeans.size());
// 这里面进行数据的传值等操作
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "onError: ");
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete: ");
}
});
示例项目已上传至GitHub
,下载地址:
https://github.com/cnwutianhao/Retrofit2/tree/master/app-RxAndroid
网友评论