前面我已经介绍过了RxJava的使用,现在我们来学习Retrofit的简单使用
Retrofit是一个当前很流行的网络请求库, 官网的介绍是: "Type-safe HTTP client for Android and Java". 本文介绍Retrofit的使用.
先介绍单独使用Retrofit进行网络请求, 后面主要介绍和RxJava结合的请求, 有实例代码.
在使用Retrofit之前我们需要在androidstudio中依赖下面三个库
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.google.code.gson:gson:2.8.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
我们现在以Git的API为例子
https://api.github.com
先建立一个实体类Endpoints
这个API实体的变量太多了这里就不放出代码了
首先我们需要写一个接口GitHubService
public interface GitHubService {
@GET
Call getAllEndpoints(@Url String url);
}
这个接口指定了一个Get请求,用来传Url的
public interface GitHubService {
@GET
Call getAllEndpoints(@Url String url);
}
public class ServiceGenerator {
private static ServiceGenerator instance;
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
private static Retrofit.Builder builder;
public ServiceGenerator(String url) {
builder = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create());
}
public static ServiceGenerator getInstance(String url){
if(null == instance){
synchronized (ServiceGenerator.class){
instance = new ServiceGenerator(url);
}
}
return instance;
}
public static S createService(Class serviceClass) {
Retrofit retrofit = builder.client(httpClient.build()).build();
return retrofit.create(serviceClass);
}
}
最后请求并得到结果
public class MainActivity extends Activity {
public static final String API_BASE_URL = "https://api.github.com";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GitHubService gitHubService = ServiceGenerator.getInstance(API_BASE_URL).createService(GitHubService.class);
Call endpointsCall = gitHubService.getAllEndpoints("");
endpointsCall.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
Endpoints endpoints = response.body();
String repositoryUrl = endpoints.getRepository_url();
Log.e("repository url:",repositoryUrl);
Toast.makeText(MainActivity.this, "repository url: " + repositoryUrl, Toast.LENGTH_LONG).show();
}
@Override
public void onFailure(Call call, Throwable t) {
}
});
}
}
public interface GitHubService {
@GET
Call getAllEndpoints(@Url String url);
@GET("users/{user}")
Call getUser(@Path("user") String user);
}
RxJava近年来很流行, 主要优势是流式操作, 可以处理并行发送请求, 使用灵活, 线程切换容易.
当你要处理的逻辑比较复杂时, 就会发现使用RxJava的优势.
以我们的例子来说, 当前我们利用一个请求可以得到一个用户的信息并显示出来.
如果我们想得到这个用户的所有repo的所有者或者其他信息, 所有他follow的人的信息, 以及他们的repo的信息呢?
这就需要发很多个请求, 并且其中有些请求是并行发送的, 如果按照前面的方法, 不断地在callback里面嵌套, 那就太难看了.
首先, 添加RxJava和RxAndroid的依赖:
compile 'io.reactivex:rxjava:1.2.2'
compile 'io.reactivex:rxandroid:1.2.1'
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
Retrofit.Builder()中加入这一行:.addCallAdapterFactory(RxJavaCallAdapterFactory.create());
public class ServiceGenerator {
public static final String API_BASE_URL = "https://api.github.com";
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create());
public static S createService(Class serviceClass) {
Retrofit retrofit = builder.client(httpClient.build()).build();
return retrofit.create(serviceClass);
}
}
现在改用RxJava了, 返回的不是Call而是Observable:
@GET("users/{user}/following")
Observable> getUserFollowingObservable(@Path("user") String user);
结合RxJava请求的时候变为这样:
GitHubService service = ServiceGenerator.createService(GitHubService.class);
String username = inputUserNameView.getText().toString();
service.getUserFollowingObservable(username)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(List users) {
LogUtils.i("onNext: " + users.size());
peopleListAdapter.setUsers(users);
peopleListAdapter.notifyDataSetChanged();
}
});
设计这样一个场景, 我们现在取到了一个用户follow的所有人, 但是取回的信息中并不包含每个人拥有的repo个数, 只有一个url可用户查看所有repo.
接下来我们要取其中每一个人的详细信息, 就要查询另一个API, 重新查询这个人的完整信息.
查询用户follow的所有人, 然后查询每一个人的详细信息:
subscription = service.getUserFollowingObservable(username)
.flatMap(new Func1, Observable>() {
@Override
public Observable call(List users) {
return Observable.from(users);
}
})
.flatMap(new Func1>() {
@Override
public Observable call(User user) {
return service.getUserObservable(user.getLogin());
}
})
.toList()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(List users) {
peopleListAdapter.setUsers(users);
peopleListAdapter.notifyDataSetChanged();
}
});
我们会发现我们每次取user数据的时候有点慢我们可以这样:
subscription = service.getUserFollowingObservable(username)
.subscribeOn(Schedulers.io()) // 从io线程开始, 取用户follow的所有人
.flatMap(new Func1, Observable>() {
@Override
public Observable call(List users) {
LogUtils.i("from");
return Observable.from(users);
}
})
.toList()
.observeOn(AndroidSchedulers.mainThread()) // 最后返回到主线程
.subscribe(new Subscriber>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(List users) {
LogUtils.i("onNext: " + users.size());
peopleListAdapter.setUsers(users);
peopleListAdapter.notifyDataSetChanged();
}
})
当我们有时跳转界面时,网络请求还没有完成,这样很可能没有请求返回,这样就可能引起内存泄漏,所以我们需要自己取消订阅
@Override
protected void onPause() {
super.onPause();
if (subscription!= null && subscription.isUnsubscribed()){
subscription.unsubscribe();
}
}
如果有多个请求, 可以用:
private CompositeSubscription compositeSubscription = new CompositeSubscription();
...
// 在发请求的地方, 返回subscription
compositeSubscription.add(subscription);
...
// 选一个生命周期注销所有请求
@Override
public void onPause() {
super.onPause();
compositeSubscription.unsubscribe();
}