okhttp java app_Android使用RxJava+Retrofit2+Okhttp+MVP练习的APP

Android使用RxJava+Retrofit2+Okhttp+MVP练习的APP

项目截图

5e582b7d20776a3539c5b63ad5953f0e.png

51505abaf34d68cbe1caa2560bc3b21d.png

8a87d29c31d6042e8daf0d9cb0992fb5.png

435650f62a4eb746d66d73283b0f7810.png

1533f4f7a5865f6cb0192c9bf0ffdfe8.png

0034b51f45486ec52796ef72abd0d7d7.png

这是我的目录结构

c434f1b7c0380cd00aa0b2d7e6a798fd.png

五步使用RxJava+Retrofit2+Okhttp+RxCache

第一步:导包

compile 'io.reactivex:rxjava:1.1.8'

compile 'io.reactivex:rxandroid:1.2.1'

compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'

compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'

compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'

compile 'com.github.VictorAlbertos.RxCache:core:1.4.6'

第二步:新建API接口

public interface GanHuoService {

@GET("data/{type}/{number}/{page}")

Observable getDataResults(

@Path("type") String type,

@Path("number") int number,

@Path("page") int page

);

}

第三步:新建缓存接口

/**

* 缓存API接口

*

* @LifeCache设置缓存过期时间. 如果没有设置@LifeCache , 数据将被永久缓存理除非你使用了 EvictProvider, EvictDynamicKey or EvictDynamicKeyGroup .

* EvictProvider可以明确地清理清理所有缓存数据.

* EvictDynamicKey可以明确地清理指定的数据 DynamicKey.

* EvictDynamicKeyGroup 允许明确地清理一组特定的数据. DynamicKeyGroup.

* DynamicKey驱逐与一个特定的键使用EvictDynamicKey相关的数据。比如分页,排序或筛选要求

* DynamicKeyGroup。驱逐一组与key关联的数据,使用EvictDynamicKeyGroup。比如分页,排序或筛选要求

*/

public interface CacheProviders {

//缓存时间 1天

@LifeCache(duration = 7, timeUnit = TimeUnit.DAYS)

Observable>> getHomeTypes(Observable observable, DynamicKey userName, EvictDynamicKey evictDynamicKey);

}

第四步:新建retrofit抽象类

public abstract class RetrofitUtils {

private static Retrofit mRetrofit;

private static OkHttpClient mOkHttpClient;

/**

* 获取Retrofit对象

*

* @return

*/

protected static Retrofit getRetrofit() {

if (null == mRetrofit) {

if (null == mOkHttpClient) {

mOkHttpClient = OkHttp3Utils.getOkHttpClient();

}

//Retrofit2后使用build设计模式

mRetrofit = new Retrofit.Builder()

//设置服务器路径

.baseUrl(Constant.API_SERVER + "/")

//添加转化库,默认是Gson

.addConverterFactory(GsonConverterFactory.create())

//添加回调库,采用RxJava

.addCallAdapterFactory(RxJavaCallAdapterFactory.create())

//设置使用okhttp网络请求

.client(mOkHttpClient)

.build();

}

return mRetrofit;

}

}

第五步:新建HttpData类 用于统一管理请求

/*

* 所有的请求数据的方法集中地

* 根据MovieService的定义编写合适的方法

* 其中observable是获取API数据

* observableCahce获取缓存数据

* new EvictDynamicKey(false) false使用缓存 true 加载数据不使用缓存

*/

public class HttpData extends RetrofitUtils {

private static File cacheDirectory = FileUtil.getcacheDirectory();

private static final CacheProviders providers = new RxCache.Builder()

.persistence(cacheDirectory)

.using(CacheProviders.class);

protected static final GanHuoService service = getRetrofit().create(GanHuoService.class);

private static class SingletonHolder {

private static final HttpData INSTANCE = new HttpData();

}

public static HttpData getInstance() {

return SingletonHolder.INSTANCE;

}

public void getHomeInfo(Observer observer, boolean isUseCache,String type, int number, int page) {

Observable observable= service.getDataResults(type,number,page);

Observable observableCahce=providers.getHomeTypes(observable,new DynamicKey("首页"),new EvictDynamicKey(!isUseCache)).map(new HttpResultFuncCcche>());

setSubscribe(observableCahce,observer);

}

/**

* 插入观察者

*

* @param observable

* @param observer

* @param

*/

public static void setSubscribe(Observable observable, Observer observer) {

observable.subscribeOn(Schedulers.io())

.subscribeOn(Schedulers.newThread())//子线程访问网络

.observeOn(AndroidSchedulers.mainThread())//回调到主线程

.subscribe(observer);

}

/**

* 用来统一处理RxCacha的结果

*/

private class HttpResultFuncCcche implements Func1, T> {

@Override

public T call(Reply httpResult) {

return httpResult.getData();

}

}

}

搭建完成,可以像这样请求数据,需要写到Model里面的

public class HomeFragmentModel {

public void loadData(final OnLoadDataListListener listener,boolean isUseCache ,String type, int number, int page) {

HttpData.getInstance().getHomeInfo(new Observer() {

@Override

public void onCompleted() {

}

@Override

public void onError(Throwable e) {

listener.onFailure(e);

}

@Override

public void onNext(DataResults homeDto) {

listener.onSuccess(homeDto);

}

}, isUseCache,type,number,page);

}

}

MVC (Model-View-Controller)

M是指逻辑模型,V是指视图模型,C则是控制器。一个逻辑模型可以对于多种视图模型

使用MVC的目的是将M和V的实现代码分离,方便扩展,便于以后的管理

从开发者的角度,MVC把应用程序的逻辑层与界面是完全分开的,最大的好处是:界面设计人员可以直接参与到界面开发,程序员就可以把精力放在逻辑层上。

虽然理论上可以实现,但实践起来还是感觉不能完全分开...Android中也可以说采用了当前比较流行的MVC框架,在Android中:1) 视图层(View):一般采用XML文件进行界面的描述,使用的时候可以非常方便的引入,但是用xml编写了,又需要在Acitvity声明并且实例化。2) 控制层(Controller):Android的控制层的重任通常落在了众多的Acitvity的肩上,要通过Activity交割Model业务逻辑层处理,这样做的另外一个原因是Android中的Acitivity的响应时间是5s,如果耗时的操作放在这里,程序就很容易被回收掉。3) 模型层(Model):对数据库的操作、对网络等的操作都应该在Model里面处理,当然对业务计算等操作也是必须放在的该层的。

MVP

MVP 就是基于MVC 的模式上的一个演化版本。在MVC模式中,Activity应该是属于View这一层。而实质上,它既承担了View,同时也包含一些Controller的东西在里面。随着项目的迭代更新,这对开发很不友好,耦合度也原来越高,项目越来越难维护,而MVP 就是解决这样的痛点。把Activity的View和Controller抽离出来就变成了View和Presenter。

MVP的优点:

模型与视图完全分离,我们可以修改视图而不影响模型

可以更高效地使用模型,因为所有的交互都发生在一个地方——Presenter内部

我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁。

如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试)

首页是Model层:业务逻辑和实体模型,所以Model层我只放业务逻辑

public class HomeFragmentModel {

public void loadData(final OnLoadDataListListener listener,boolean isUseCache ,String type, int number, int page) {

HttpData.getInstance().getHomeInfo(new Observer() {

@Override

public void onCompleted() {

}

@Override

public void onError(Throwable e) {

listener.onFailure(e);

}

@Override

public void onNext(DataResults homeDto) {

listener.onSuccess(homeDto);

}

}, isUseCache,type,number,page);

}

}

然后是view层: View 对应于Activity或者fragment,负责View的绘制以及与用户交互

public interface HomeFragmentView {

//显示加载页

void showProgress();

//关闭加载页

void hideProgress();

//加载新数据

void newDatas(DataResults data);

//显示加载失败

void showLoadFailMsg();

}

然后就是Presenter 负责完成View于Model间的交互

public class HomePresenter implements OnLoadDataListListener {

private HomeFragmentView mView;

private HomeFragmentModel mModel;

public HomePresenter(HomeFragmentView mView) {

this.mView = mView;

this.mModel=new HomeFragmentModel();

mView.showProgress();

}

public void getDataResults(boolean isUseCache,String type, int number, int page) {

mModel.loadData(this,isUseCache,type,number,page);

}

@Override

public void onSuccess(DataResults data) {

mView.newDatas(data);

mView.hideProgress();

}

@Override

public void onFailure(Throwable e) {

Log.e("onFailure",e.toString());

mView.showLoadFailMsg();

}

}

最终回到Activity或者fragment

public class DiscoveryFragment extends BaseFragment implements HomeFragmentView {

private HomePresenter homePresenter;

@Override

protected View initView(LayoutInflater inflater, ViewGroup container) {

return inflater.inflate(R.layout.fragment_list, container, false);

}

@Override

protected void initData(Bundle savedInstanceState) {

homePresenter = new HomePresenter(this);

}

@Override

protected void loadData() {

getData(isFirst);

}

private void getData(boolean isUseCache) {

switch (mTitle) {

case "首页":

if (isTop) {

NOW_PAGE_FI = 1;

}

homePresenter.getDataResults(isUseCache,"all", fi_num, NOW_PAGE_FI);

break;

}

}

@Override

public void newDatas(DataResults dataResults) {

if (dataResults.isError()) {

Snackbar.make(recyclerview, "服务器出问题啦", Snackbar.LENGTH_SHORT).show();

} else {

if (mTitle.equals("干货")) {

ganhuo_list = new ArrayList<>();

ganhuo_list.addAll(dataResults.getResults());

}

}

}

private void clearAdapterResults() {

switch (mTitle) {

case "首页":

partAdapter.getResults().clear();

break;

case "妹纸":

girlyAdapter.getResults().clear();

break;

}

}

@Override

public void showLoadFailMsg() {

Snackbar.make(recyclerview, "网络不顺畅嘞,更新不了数据啦", Snackbar.LENGTH_SHORT).show();

}

@Override

public void showProgress() {

}

@Override

public void hideProgress() {

}

}

项目地址,欢迎star:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值