工程目录结构
目前网上的mvp框架大多存在以下问题:
1,Presenter持有View的引用,容易导致出现内存泄漏
MvpPresenter mvpPresenter = new MvpPresenter(this); // 不推荐这样写,持有activty引用,容易出现内存泄露
2,如果每一个Activity都对应一个Model和Presenter的话,试想一下,如果有几百个Activity的话那么是不是也要创建很多个Model和Presenter,关键是很多地方都是重复的可以通用的。所以,创建基类就显得很有必要了,具体查看本例写法,优不优雅看过之后您评论。
添加依赖
// Retrofit
compile 'com.squareup.retrofit2:retrofit:2.4.0'
// Retrofit和jxjava关联
compile 'com.squareup.retrofit2:adapter-rxjava2:2.4.0'
// Retrofit使用Gson转换
compile 'com.squareup.retrofit2:converter-gson:2.4.0'
// RxJava
compile 'io.reactivex.rxjava2:rxjava:2.1.12'
// RxAndroid
compile 'io.reactivex.rxjava2:rxandroid:2.0.2'
1,RetrofitHelper
主要用于Retrofit的初始化:
// 声明Retrofit对象
private Retrofit mRetrofit = null;
OkHttpClient client = new OkHttpClient();
// 由于该对象会被频繁调用,采用单例模式,下面是一种线程安全模式的单例写法,构造方法已被private修饰
private volatile static RetrofitHelper instance = null;
public static RetrofitHelper getInstance(){
if (instance == null){
synchronized (RetrofitHelper.class) {
if(instance == null){
instance = new RetrofitHelper();
}
}
}
return instance;
}
private RetrofitHelper(){
initRetrofit();
}
/**
* 初始化 retrofit
*/
private void initRetrofit() {
mRetrofit = new Retrofit.Builder()
.baseUrl(UrlConstant.BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}
public RetrofitService getServer(){
return mRetrofit.create(RetrofitService.class);
}
其中getServer方法就是为了获取RetrofitService接口类的实例化。然后定义了一个静态方法getInstance用于获取自身RetrofitHelper的实例化,并且只会实例化一次。
2,RetrofitService
public interface RetrofitService {
@GET("book/search")
Observable<Book> getSearchBooks(@Query("q") String name,
@Query("tag") String tag, @Query("start") int start,
@Query("count") int count);
}
3,DataManager
/**
* 该类用来管理RetrofitService中对应的各种API接口
* 当做Retrofit和presenter中的桥梁,Activity就不用直接和retrofit打交道了
*/
public class DataManager {
private RetrofitService mRetrofitService;
private DataManager(){
this.mRetrofitService = RetrofitHelper.getInstance().getServer();
}
//由于该对象会被频繁调用,采用单例模式,下面是一种线程安全模式的单例写法,构造方法已被private修饰
private volatile static DataManager instance;
public static DataManager getInstance() {
if (instance == null) {
synchronized (DataManager.class) {
if (instance == null) {
instance = new DataManager();
}
}
}
return instance;
}
// 将retrofit的业务方法映射到DataManager中,以后统一用该类来调用业务方法
// 以后在RetrofitService中增加业务方法的时候,相应的这里也要添加一个方法,建议方法名字相一致
public Observable<Book> getSearchBooks(String name, String tag, int start, int count){
return mRetrofitService.getSearchBooks(name,tag,start,count);
}
}
这个类其实就是为了让你更方便的调用RetrofitService 中定义的方法,可以看到,在它的构造方法中,我们得到了RetrofitService 的实例化,然后定义了一个和RetrofitService 中同名的方法,里面其实就是调用RetrofitService 中的这个方法。这样,把RetrofitService 中定义的方法都封装到DataManager 中,以后无论在哪个要调用方法时直接在DataManager 中调用就可以了,而不是重复建立RetrofitService 的实例化,再调用其中的方法。
4,其中bean下放我们请求的实体类,这里就是Book
package com.gpf.mvp.service.bean;
import java.util.List;
/**
* Created by Administrator on 2018/11/23.
*/
public class Book {
/**
* count : 1
* start : 0
* total : 20
* books : [{"rating":{"max":10,"numRaters":3342,"average":"7.9","min":0},"subtitle":"西北有雏凤","author":["烽火戏诸侯"],"pubdate":"2013-9-1","tags":[{"count":520,"name":"烽火戏诸侯","title":"烽火戏诸侯"},{"count":477,"name":"武侠","title":"武侠"},{"count":436,"name":".好书,很值得一看。","title":".好书,很值得一看。"},{"count":381,"name":"雪中悍刀行,你值得拥有","title":"雪中悍刀行,你值得拥有"},{"count":365,"name":"达到了我对武侠江湖的那个感觉~人物特点脱出。文笔好。。希望烽火","title":"达到了我对武侠江湖的那个感觉~人物特点脱出。文笔好。。希望烽火"},{"count":301,"name":"小说","title":"小说"},{"count":276,"name":"新武侠","title":"新武侠"},{"count":208,"name":"玄幻","title":"玄幻"}],"origin_title":"小二 上酒","image":"https://img3.doubanio.com/view/subject/m/public/s27142913.jpg","binding":"平装","translator":[],"catalog":"第一章 六千里归乡上酒,白狐脸佩刀入城\n老仆笑得很淳朴很灿烂,一张老脸像只有出了远门到了荒郊才能瞅见的大片芦苇丛,可能谈不上旖旎或者壮阔,却有着自己的情怀。\n第二章 武媚娘遥望城头,湖心里老魁带刀\n枯槁如鬼的男人开口,如一股子金石声,\u201c从一品。阁内修行十年,可此下众生,此上无人。\u201d\n第三章 莲花峰骑牛问道,武帝城竖剑留语\n洪洗象等世子殿下走远了,然后姿势不雅地蹲着,双手托着腮帮,怔怔出神,喃喃自语:\u201c红豆生南国,春来发枝冬凋敝,相思不如不相思。\u201d\n第四章 赴城外杀人赏雪,上武当姜泥送书\n天底下什么东西最重?情义?忠孝?放屁,是书最重。\n第五章 拔悍刀血战双卫,大庚角留帖离山\n徐凤年记起三年游历中在洛水河畔,远远看到的一个窈窕背影,怔怔出神道:\u201c相思刀最是能杀人。\n第六章 老掌教黄庭作嫁,小和尚秀色参禅\n你便是我的禅,秀色可\u201c参\u201d。\n第七章 北凉歌再奠英灵,阴阳间喝酒换刀\n白狐儿脸说了句几乎让徐凤年吐血的话,\u201c你要是女人就好了,我便娶了你。\u201d\n第八章 忆王妃老卒瞑目,出凉州世子挎刀\n徐凤年丢掉树叶,膝上叠放着绣冬、春雷双刀,望着墓碑柔声道:\u201c娘,你的仇,徐骁不报,凤年还记着呢。\u201d\n第九章 红符甲大雨拦道,老剑神初显身手\n魏爷爷,你说一品有四重,金刚之上是指玄。原来一弹玄机即指玄。\n第十章 晋兰亭鱼跃龙门,青城山怒斩马贼\n\u201c温华,没钱买不起好剑又何妨,希望你小子能一直提着把破木剑去名动天下。到时候按照兄弟约定,你请我吃牛肉,我给你叫好。\u201d\n第十一章 山河图随行细绘,青羊宫闯阵玉宵\n北凉铁骑甲天下,不是靠文人士子用嘴喊出来的,而是马踏六国加上半座江湖一个一个铁蹄踩踏出来的!\n第十二章 滚刀术先手五十,北凉王悍然入宫\n他便一直擦下去,哽咽着温柔道:\u201c姑姑好看,姑姑不哭。\u201d","pages":"320","images":{"small":"https://img3.doubanio.com/view/subject/s/public/s27142913.jpg","large":"https://img3.doubanio.com/view/subject/l/public/s27142913.jpg","medium":"https://img3.doubanio.com/view/subject/m/public/s27142913.jpg"},"alt":"https://book.douban.com/subject/25714176/","id":"25714176","publisher":"江苏文艺出版社","isbn10":"7539962879","isbn13":"9787539962870","title":"雪中悍刀行 1","url":"https://api.douban.com/v2/book/25714176","alt_title":"小二 上酒","author_intro":"2005年底烽火开始在起点中文网发文,后一直以挖\u201c坑\u201d不填而广受读者抱怨,因此被称为\u201c大内太监总管\u201d。 代表作《陈二狗的妖孽人生》《极品公子》《天神下凡》等\n其作品订阅极高、口碑极好,但是他毅然太监,绝不\u201c出宫\u201d。更新速度犹如龟爬,马甲众多!其马甲有:婆娑世界教主、八部浮屠。\n2010年4月,烽火转战纵横中文网。如今,他毅然\u201c出宫\u201d,更是执着一把悍刀,带着第一本完美收官之作征这出版之道!试问,八百白袍,今安在?","summary":"道门真人飞天入地,千里取人首级;佛家菩萨低眉怒目,抬手可撼昆仑;谁又言书生无意气,一怒敢叫天子露戚容。踏江踏湖踏歌,我有一剑仙人跪;提刀提剑提酒,三十万铁骑征天。\n老仆剑九背匣,吕祖修道骑牛,天道悠悠难觅,情之一字可杀人。\n漠北黄沙如刀舞, 世子白马出北凉,身后跟着一百佩刀甲士。\n鲜衣怒马,美婢娇娘,还有一个抠脚的断臂老人。\n犹记得跟缺门牙老黄的那段对话。\n\u201c老黄,你是高手吗?\u201d\n\u201c是哩。\u201d\n\u201c有多高?\u201d\n\u201c啧啧,只比公子差一点点。\u201d\n回想当初自己不屑地吐出黄瓜花儿,还骂了句去你娘的。却不承想,那老黄乃是传说中高手中的高手。这世道果然难测。\n世子如今带双刀,剑神武夫,江湖庙堂,可否一并斩之?","series":{"id":"20883","title":"雪中悍刀行"},"price":"25.00元"}]
*/
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 {
/**
* rating : {"max":10,"numRaters":3342,"average":"7.9","min":0}
* subtitle : 西北有雏凤
* author : ["烽火戏诸侯"]
* pubdate : 2013-9-1
* tags : [{"count":520,"name":"烽火戏诸侯","title":"烽火戏诸侯"},{"count":477,"name":"武侠","title":"武侠"},{"count":436,"name":".好书,很值得一看。","title":".好书,很值得一看。"},{"count":381,"name":"雪中悍刀行,你值得拥有","title":"雪中悍刀行,你值得拥有"},{"count":365,"name":"达到了我对武侠江湖的那个感觉~人物特点脱出。文笔好。。希望烽火","title":"达到了我对武侠江湖的那个感觉~人物特点脱出。文笔好。。希望烽火"},{"count":301,"name":"小说","title":"小说"},{"count":276,"name":"新武侠","title":"新武侠"},{"count":208,"name":"玄幻","title":"玄幻"}]
* origin_title : 小二 上酒
* image : https://img3.doubanio.com/view/subject/m/public/s27142913.jpg
* binding : 平装
* translator : []
* catalog : 第一章 六千里归乡上酒,白狐脸佩刀入城
老仆笑得很淳朴很灿烂,一张老脸像只有出了远门到了荒郊才能瞅见的大片芦苇丛,可能谈不上旖旎或者壮阔,却有着自己的情怀。
第二章 武媚娘遥望城头,湖心里老魁带刀
枯槁如鬼的男人开口,如一股子金石声,“从一品。阁内修行十年,可此下众生,此上无人。”
第三章 莲花峰骑牛问道,武帝城竖剑留语
洪洗象等世子殿下走远了,然后姿势不雅地蹲着,双手托着腮帮,怔怔出神,喃喃自语:“红豆生南国,春来发枝冬凋敝,相思不如不相思。”
第四章 赴城外杀人赏雪,上武当姜泥送书
天底下什么东西最重?情义?忠孝?放屁,是书最重。
第五章 拔悍刀血战双卫,大庚角留帖离山
徐凤年记起三年游历中在洛水河畔,远远看到的一个窈窕背影,怔怔出神道:“相思刀最是能杀人。
第六章 老掌教黄庭作嫁,小和尚秀色参禅
你便是我的禅,秀色可“参”。
第七章 北凉歌再奠英灵,阴阳间喝酒换刀
白狐儿脸说了句几乎让徐凤年吐血的话,“你要是女人就好了,我便娶了你。”
第八章 忆王妃老卒瞑目,出凉州世子挎刀
徐凤年丢掉树叶,膝上叠放着绣冬、春雷双刀,望着墓碑柔声道:“娘,你的仇,徐骁不报,凤年还记着呢。”
第九章 红符甲大雨拦道,老剑神初显身手
魏爷爷,你说一品有四重,金刚之上是指玄。原来一弹玄机即指玄。
第十章 晋兰亭鱼跃龙门,青城山怒斩马贼
“温华,没钱买不起好剑又何妨,希望你小子能一直提着把破木剑去名动天下。到时候按照兄弟约定,你请我吃牛肉,我给你叫好。”
第十一章 山河图随行细绘,青羊宫闯阵玉宵
北凉铁骑甲天下,不是靠文人士子用嘴喊出来的,而是马踏六国加上半座江湖一个一个铁蹄踩踏出来的!
第十二章 滚刀术先手五十,北凉王悍然入宫
他便一直擦下去,哽咽着温柔道:“姑姑好看,姑姑不哭。”
* pages : 320
* images : {"small":"https://img3.doubanio.com/view/subject/s/public/s27142913.jpg","large":"https://img3.doubanio.com/view/subject/l/public/s27142913.jpg","medium":"https://img3.doubanio.com/view/subject/m/public/s27142913.jpg"}
* alt : https://book.douban.com/subject/25714176/
* id : 25714176
* publisher : 江苏文艺出版社
* isbn10 : 7539962879
* isbn13 : 9787539962870
* title : 雪中悍刀行 1
* url : https://api.douban.com/v2/book/25714176
* alt_title : 小二 上酒
* author_intro : 2005年底烽火开始在起点中文网发文,后一直以挖“坑”不填而广受读者抱怨,因此被称为“大内太监总管”。 代表作《陈二狗的妖孽人生》《极品公子》《天神下凡》等
其作品订阅极高、口碑极好,但是他毅然太监,绝不“出宫”。更新速度犹如龟爬,马甲众多!其马甲有:婆娑世界教主、八部浮屠。
2010年4月,烽火转战纵横中文网。如今,他毅然“出宫”,更是执着一把悍刀,带着第一本完美收官之作征这出版之道!试问,八百白袍,今安在?
* summary : 道门真人飞天入地,千里取人首级;佛家菩萨低眉怒目,抬手可撼昆仑;谁又言书生无意气,一怒敢叫天子露戚容。踏江踏湖踏歌,我有一剑仙人跪;提刀提剑提酒,三十万铁骑征天。
老仆剑九背匣,吕祖修道骑牛,天道悠悠难觅,情之一字可杀人。
漠北黄沙如刀舞, 世子白马出北凉,身后跟着一百佩刀甲士。
鲜衣怒马,美婢娇娘,还有一个抠脚的断臂老人。
犹记得跟缺门牙老黄的那段对话。
“老黄,你是高手吗?”
“是哩。”
“有多高?”
“啧啧,只比公子差一点点。”
回想当初自己不屑地吐出黄瓜花儿,还骂了句去你娘的。却不承想,那老黄乃是传说中高手中的高手。这世道果然难测。
世子如今带双刀,剑神武夫,江湖庙堂,可否一并斩之?
* series : {"id":"20883","title":"雪中悍刀行"}
* price : 25.00元
*/
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 SeriesBean series;
private String price;
private List<String> author;
private List<TagsBean> tags;
private List<?> 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 SeriesBean getSeries() {
return series;
}
public void setSeries(SeriesBean series) {
this.series = series;
}
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<?> getTranslator() {
return translator;
}
public void setTranslator(List<?> translator) {
this.translator = translator;
}
@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 + '\'' +
", series=" + series +
", price='" + price + '\'' +
", author=" + author +
", tags=" + tags +
", translator=" + translator +
'}';
}
public static class RatingBean {
/**
* max : 10
* numRaters : 3342
* average : 7.9
* min : 0
*/
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;
}
}
public static class ImagesBean {
/**
* small : https://img3.doubanio.com/view/subject/s/public/s27142913.jpg
* large : https://img3.doubanio.com/view/subject/l/public/s27142913.jpg
* medium : https://img3.doubanio.com/view/subject/m/public/s27142913.jpg
*/
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;
}
}
public static class SeriesBean {
/**
* id : 20883
* title : 雪中悍刀行
*/
private String id;
private String title;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
public static class TagsBean {
/**
* count : 520
* name : 烽火戏诸侯
* title : 烽火戏诸侯
*/
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 "Book{" +
"count=" + count +
", start=" + start +
", total=" + total +
", books=" + books +
'}';
}
}
5,创建抽象类BasePresenter,代码如下:
public abstract class BasePresenter<V extends BaseView> {
private V baseView;
public void attachView(V baseView) {
this.baseView = baseView;
}
/**
* 解绑View
*/
public void detachView(){
baseView = null;
}
/**
* 获取View
* @return
*/
public V getMvpView(){
return baseView;
}
}
6,创建接口BaseView,代码如下:
/**
* 定义通用的接口方法
*/
public interface BaseView {
// 显示进度框
void showProgressDialog();
// 关闭进度框
void hideProgressDialog();
// 出错信息的回调
void onError(String result);
}
7,创建BaseActivity,代码如下:
public abstract class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutId());
initPresenter();
//初始化控件,一般在BaseActivity中通过ButterKnife来绑定,所以该方法内部一般我们初始化界面相关的操作
initViews();
//获取数据
getDataFromServer();
}
// 设置布局
protected abstract int getLayoutId();
// 初始化界面
protected abstract void initViews();
// 获取数据
protected void getDataFromServer(){}
// 实例化presenter
protected void initPresenter(){}
}
8,创建BaseMvpActivity,代码如下:
public abstract class BaseMvpActivity<V extends BaseView, P extends BasePresenter<V>> extends BaseActivity {
private P presenter;
@Override
protected void initPresenter() {
//实例化Presenter
presenter = createPresenter();
//绑定
if (presenter != null){
presenter.attachView((V) this);
}
}
// 初始化Presenter
protected abstract P createPresenter();
protected P getPresenter(){
return presenter;
}
@Override
protected void onDestroy() {
//解绑
if (presenter != null){
presenter.detachView();
}
super.onDestroy();
}
}
9,UrlConstant类代码如下:
public class UrlConstant {
public static final String BASE_URL = "https://api.douban.com/v2/";
}
经过以上的步骤针对该baseurl的mvp框架就已经搭建完毕了,如果使用其他网络框架如OkGo等,前三步可以直接跳过不写,因为前三步主要是针对Retrofit网络请求过程的封装,接下来我们来实现请求接口数据,获取服务器端返回的数据。
1,根据具体的业务需求创建BaseView的接口,此处为BookView:
/**
* 根据具体的业务需求,定义特有的方法,该接口为所有的view公用
* 不同的activity定义不同的View,这些View有个共同点,那就是都继承自BaseView
*/
public interface BookView extends BaseView {
// 当前页面比较简单仅仅是获取接口数据进行展示,
// 业务比较复杂的时候,可能一个页面需要不同的接口得到不同的数据类型
void onSuccess(Book mBook);
//获取到广告位数据
// void loadBannerSuccess(BannerBean bean);
}
2,根据具体的业务需求创建BasePresenter的实现类,此处为BookPresenter:
public class BookPresenter extends BasePresenter<BookView> {
private DataManager dataManager;
private Book mBook;
public BookPresenter() {
dataManager = DataManager.getInstance();
}
public void getSearchBooks(String name,String tag,int start,int count){
if(getMvpView() != null){
// 显示进度提示
getMvpView().showProgressDialog();
// 进行网络请求
dataManager.getSearchBooks(name,tag,start,count)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Book>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull Book book) {
mBook = book;
}
// 此处注意:onComplete和onError只会调用其中一个,不可能同时被触发
@Override
public void onError(@NonNull Throwable e) {
// 在事件处理过程中出异常时,onError() 会被触发,同时队列自动终止,不允许再有事件发出
e.printStackTrace();
getMvpView().onError("请求失败!!");
getMvpView().hideProgressDialog();
}
@Override
public void onComplete() {
// onComplete方法和onError方法是互斥的,
// RxJava 规定,当不会再有新的 onNext() 发出时,需要触发 onCompleted() 方法作为标志。
if (mBook != null){
getMvpView().onSuccess(mBook);
}
// 隐藏进度
getMvpView().hideProgressDialog();
}
});
}
}
}
3,接下来就是BookActivity的实现了,注意此处继承的是BaseMvpActivity,布局文件也很简单一个textview和一个button,点击button将获取到的数据显示在textView上即可:
public class BookActivity extends BaseMvpActivity<BookView,BookPresenter> implements BookView {
private ProgressDialog progressDialog;
private Button button;
private TextView text;
@Override
protected int getLayoutId() {
return R.layout.activity_book;
}
// 获取presenter实例
@Override
protected BookPresenter createPresenter() {
return new BookPresenter();
}
// 初始化界面
@Override
protected void initViews() {
button = (Button) findViewById(R.id.button);
text = (TextView) findViewById(R.id.text);
progressDialog = new ProgressDialog(this);
progressDialog.setCancelable(false);
progressDialog.setMessage("正在拼命加载中...");
}
// 按钮的点击事件:请求接口,获取网络数据
public void getData(View view){
// 调用presenter层的方法执行网络请求
getPresenter().getSearchBooks("天涯明月刀", null, 0, 1);
}
@Override
public void onSuccess(Book mBook) {
// 将获取到的数据的信息显示在TextView组件上
text.setText(mBook.toString());
}
// 或者通过设置progress组件的VISIBLE和GONE来控制进度提示的显示和隐藏,此处是使用对话框提示
@Override
public void showProgressDialog() {
if(!progressDialog.isShowing()){
progressDialog.show();
}
}
@Override
public void hideProgressDialog() {
if(progressDialog.isShowing()){
progressDialog.dismiss();
}
}
@Override
public void onError(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
}