本文主要介绍Retrofit、RxJava和OkHttp使用。需要添加依赖:
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
compile 'io.reactivex.rxjava2:rxjava:2.1.7'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
compile 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'
这里需要注意RxJava的版本问题,如果使用的是RxJava2,那么一定要使用adapter-rxjava2,否则在编码时会找不到相关的类。
Retrofit单独使用
- Retrofit的请求是通过注解来实现的,需要先建一个接口类。
public interface RetrofitService {
@GET("book/search")
Call<Book> getBook(@Query("q") String name,
@Query("tag") String tag,
@Query("start") int start,
@Query("count") int count);
}
这是一个get请求,"book/search"是用来拼接请求url的,@Query("tag") String tag是用来传入请求参数的。
- 得到Call对象执行网络请求
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.douban.com/v2/")
.addConverterFactory(GsonConverterFactory.create())
.build();
RetrofitService retrofitService = retrofit.create(RetrofitService.class);
Call<Book> call = retrofitService.getBook("西游记", null, 0, 1);
call.enqueue(new Callback<Book>() {
@Override
public void onResponse(Call<Book> call, Response<Book> response) {
Book book = response.body();
mTvContent.setText(book + "");
}
@Override
public void onFailure(Call<Book> call, Throwable t) {
}
});
这是Retrofit单独使用时候的用法。新建一个Retrofit对象,用这个Retrofit对象通过接口类可以得到一个Call对象,直接用这个Call对象发起网络请求,里面有两个回调方法供我们处理请求结果。
Retrofit和RxJava使用
- 在接口类中再写一个方法
public interface RetrofitService {
@GET("book/search")
Call<Book> getBook(@Query("q") String name,
@Query("tag") String tag,
@Query("start") int start,
@Query("count") int count);
@GET("book/search")
Observable<Book> getSearchBook(@Query("q") String name,
@Query("tag") String tag,
@Query("start") int start,
@Query("count") int count);
}
可以看到,两个方法的写法都一样,只是返回值由Call对象变成了RxJava中的Observable对象。
关于RxJava的介绍,可以阅读以下这篇文章
给 Android 开发者的 RxJava 详解
- 得到Observable对象执行网络请求
Retrofit retrofitRxjava = new Retrofit.Builder()
.baseUrl("https://api.douban.com/v2/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
RetrofitService retrofitService1 = retrofitRxjava.create(RetrofitService.class);
Observable<Book> observable = retrofitService1.getSearchBook("西游记", null, 0, 1);
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Book>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
Log.d("AAA", "aaa");
}
@Override
public void onNext(@NonNull Book book) {
Log.d("BBB", "bbb");
mTvContent.setText(book + "");
}
@Override
public void onError(@NonNull Throwable e) {
Log.d("DDD", "ddd");
}
@Override
public void onComplete() {
Log.d("CCC", "ccc");
}
});
基本步骤都是一样的,在构建Retrofit对象时,我们多添加了addCallAdapterFactory(RxJava2CallAdapterFactory.create())这一行代码,网络请求的回调方法也发生了改变。
四个回调方法,先执行onSubscribe()方法,表示订阅完成;然后执行onNext()方法,在这个方法中,我们可以获取网络请求的结果,并进行处理(在这个Demo中,请求得到一个Book对象,把Book对象中的文本内容显示在一个TextView中);最后执行onComplete()方法,表示整个网络请求过程完成。可以从下图的log日志中看到它们的执行顺序。
这是Demo请求成功之后的效果图。
如果网络请求失败,则会执行onError()方法。这里我把网络关闭了,onError()方法报错显示无法连接上那个地址。注意这里只会执行onSubscribe()方法和onError()方法,不会再执行onNext()方法,也不会执行onComplete()方法。
Retrofit、RxJava和OkHttp一起使用
在了解了Retrofit、RxJava的使用之后,再加入一个OkHttp。其实这并不复杂,Retrofit内部也是通过OkHttp来实现网络请求的。我们可以用自己定义的OkHttpClient来代替Retrofit默认的OkHttpClient,然后在自定义的OkHttpClient中添加一些配置,比如配置网络请求的超时时间、配置缓存等等。
我们对Retrofit的网络请求进行一个简单的二次封装,这样在Activity或Fragment中使用起来更加方便,代码更加简洁,可维护程度更高。
新建一个RetrofitInstance类。在RetrofitInstance类中,创建一个OkHttpClient对象,配置了它的超时时间。再写一个单例模式,返回Retrofit对象,并且把自定义的OkHttpClient设置进去。(通过自定义的OkHttpClient,我们可以对网络请求做很多配置,具体请参考OkHttp使用教程)
public class RetrofitInstance {
private static Retrofit sInstance;
private static OkHttpClient mClient = new OkHttpClient().newBuilder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.build();
private RetrofitInstance() {
}
public static Retrofit getRetrofitInstance() {
if (sInstance == null) {
synchronized (RetrofitInstance.class) {
if (sInstance == null) {
sInstance = new Retrofit.Builder()
.client(mClient)
.baseUrl("https://api.douban.com/v2/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}
}
}
return sInstance;
}
}
在Activity中使用Retrofit网络请求,不用每次都新建Retrofit对象,直接使用单例方法来获取就行了。回调方法和前面的也还是一样的。
RetrofitService retrofitService2 = RetrofitInstance.getRetrofitInstance().create(RetrofitService.class);
Observable<Book> bookObservable = retrofitService2.getSearchBook("西游记", null, 0, 1);
bookObservable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Book>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
Log.d("AAA", "aaa");
}
@Override
public void onNext(@NonNull Book book) {
Log.d("BBB", "bbb");
mTvContent.setText(book + "");
}
@Override
public void onError(@NonNull Throwable e) {
Log.d("DDD", e.toString());
}
@Override
public void onComplete() {
Log.d("CCC", "ccc");
}
});
这就是Retrofit、RxJava和OkHttp最基本的使用。也许看起来代码还是挺多的,那是因为RxJava的强大之处远不在此,遇到复杂的情况才能体现出它的优越性。如果你感兴趣,推荐你阅读一下这篇文章给 Android 开发者的 RxJava 详解。
最后附上Book实体类的代码(因为比较长)。
public class Book {
private int count;
private int start;
private int total;
private List<BooksBean> books;
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public int getStart() {
return start;
}
public void setStart(int start) {
this.start = start;
}
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public List<BooksBean> getBooks() {
return books;
}
public void setBooks(List<BooksBean> books) {
this.books = books;
}
public static class BooksBean {
private RatingBean rating;
private String subtitle;
private String pubdate;
private String origin_title;
private String image;
private String binding;
private String catalog;
private String pages;
private ImagesBean images;
private String alt;
private String id;
private String publisher;
private String isbn10;
private String isbn13;
private String title;
private String url;
private String alt_title;
private String author_intro;
private String summary;
private String price;
private List<String> author;
private List<TagsBean> tags;
private List<String> translator;
public RatingBean getRating() {
return rating;
}
public void setRating(RatingBean rating) {
this.rating = rating;
}
public String getSubtitle() {
return subtitle;
}
public void setSubtitle(String subtitle) {
this.subtitle = subtitle;
}
public String getPubdate() {
return pubdate;
}
public void setPubdate(String pubdate) {
this.pubdate = pubdate;
}
public String getOrigin_title() {
return origin_title;
}
public void setOrigin_title(String origin_title) {
this.origin_title = origin_title;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
public String getBinding() {
return binding;
}
public void setBinding(String binding) {
this.binding = binding;
}
public String getCatalog() {
return catalog;
}
public void setCatalog(String catalog) {
this.catalog = catalog;
}
public String getPages() {
return pages;
}
public void setPages(String pages) {
this.pages = pages;
}
public ImagesBean getImages() {
return images;
}
public void setImages(ImagesBean images) {
this.images = images;
}
public String getAlt() {
return alt;
}
public void setAlt(String alt) {
this.alt = alt;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPublisher() {
return publisher;
}
public void setPublisher(String publisher) {
this.publisher = publisher;
}
public String getIsbn10() {
return isbn10;
}
public void setIsbn10(String isbn10) {
this.isbn10 = isbn10;
}
public String getIsbn13() {
return isbn13;
}
public void setIsbn13(String isbn13) {
this.isbn13 = isbn13;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getAlt_title() {
return alt_title;
}
public void setAlt_title(String alt_title) {
this.alt_title = alt_title;
}
public String getAuthor_intro() {
return author_intro;
}
public void setAuthor_intro(String author_intro) {
this.author_intro = author_intro;
}
public String getSummary() {
return summary;
}
public void setSummary(String summary) {
this.summary = summary;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public List<String> getAuthor() {
return author;
}
public void setAuthor(List<String> author) {
this.author = author;
}
public List<TagsBean> getTags() {
return tags;
}
public void setTags(List<TagsBean> tags) {
this.tags = tags;
}
public List<String> getTranslator() {
return translator;
}
public void setTranslator(List<String> translator) {
this.translator = translator;
}
public static class RatingBean {
private int max;
private int numRaters;
private String average;
private int min;
public int getMax() {
return max;
}
public void setMax(int max) {
this.max = max;
}
public int getNumRaters() {
return numRaters;
}
public void setNumRaters(int numRaters) {
this.numRaters = numRaters;
}
public String getAverage() {
return average;
}
public void setAverage(String average) {
this.average = average;
}
public int getMin() {
return min;
}
public void setMin(int min) {
this.min = min;
}
@Override
public String toString() {
return "RatingBean{" +
"max=" + max +
", numRaters=" + numRaters +
", average='" + average + '\'' +
", min=" + min +
'}';
}
}
public static class ImagesBean {
private String small;
private String large;
private String medium;
public String getSmall() {
return small;
}
public void setSmall(String small) {
this.small = small;
}
public String getLarge() {
return large;
}
public void setLarge(String large) {
this.large = large;
}
public String getMedium() {
return medium;
}
public void setMedium(String medium) {
this.medium = medium;
}
@Override
public String toString() {
return "ImagesBean{" +
"small='" + small + '\'' +
", large='" + large + '\'' +
", medium='" + medium + '\'' +
'}';
}
}
public static class TagsBean {
private int count;
private String name;
private String title;
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
@Override
public String toString() {
return "BooksBean{" +
"rating=" + rating +
", subtitle='" + subtitle + '\'' +
", pubdate='" + pubdate + '\'' +
", origin_title='" + origin_title + '\'' +
", image='" + image + '\'' +
", binding='" + binding + '\'' +
", catalog='" + catalog + '\'' +
", pages='" + pages + '\'' +
", images=" + images +
", alt='" + alt + '\'' +
", id='" + id + '\'' +
", publisher='" + publisher + '\'' +
", isbn10='" + isbn10 + '\'' +
", isbn13='" + isbn13 + '\'' +
", title='" + title + '\'' +
", url='" + url + '\'' +
", alt_title='" + alt_title + '\'' +
", author_intro='" + author_intro + '\'' +
", summary='" + summary + '\'' +
", price='" + price + '\'' +
", author=" + author +
", tags=" + tags +
", translator=" + translator +
'}';
}
}
@Override
public String toString() {
return "Book{" +
"count=" + count +
", start=" + start +
", total=" + total +
", books=" + books +
'}';
}
}