我这里的网络请求是用的装饰者模式去写的,什么是装饰者模式呢?在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。我的理解就是一个接口,两个实现类,一个实现类负责调用接口的方法,另一个类负责功能的具体实现。本文中所提到的代码都是伪代码,最后会给出完整的,最初版本的项目框架。不包含任何业务逻辑

 
项目结构.png

  容我一个一个来说,首先,我们一般请求网络的时候,会有统一的返回数据格式,一个是需要判断返回code码的,就比方说登录功能,那登录成功,还是失败,我们只用判断code码即可,这种类型,我们统一是HttpNoResult。还有一个是返回数据的,就比方说查一个列表数据。这里我们统一的是HttpResult。我先给出这两个类的代码:

package com.haichenyi.myproject.model.http;

/**
* Author: 海晨忆
* Date: 2018/2/23
* Desc:没有解析数据的返回
*/
public class HttpNoResult {
private int code;
private String msg; public int getCode() {
return code;
} public HttpNoResult setCode(int code) {
this.code = code;
return this;
} public String getMsg() {
return msg;
} public HttpNoResult setMsg(String msg) {
this.msg = msg;
return this;
} @Override
public String toString() {
return "HttpNoResult{" + "code=" + code + ", msg='" + msg + '\'' + '}';
}
}
package com.haichenyi.myproject.model.http;

import com.google.gson.annotations.SerializedName;

/**
* Author: 海晨忆
* Date: 2018/2/23
* Desc:有解析数据的返回
*/
public class HttpResult<T> {
private int code;
private String msg;
@SerializedName(value = "result")
private T data; public int getCode() {
return code;
} public HttpResult setCode(int code) {
this.code = code;
return this;
} public String getMsg() {
return msg;
} public HttpResult setMsg(String msg) {
this.msg = msg;
return this;
} public T getData() {
return data;
} public HttpResult setData(T data) {
this.data = data;
return this;
} @Override
public String toString() {
return "HttpResult{" + "code=" + code + ", msg='" + msg + '\'' + ", data=" + data + '}';
}
}

 这里我就需要说一点,有数据返回的时候,每个数据类型都是不一样的,所以,这里我用的泛型传递,不同的数据类型,传不同的bean对象

  言归正传,我们来说说网络请求的一个接口,两个实现类。

一个接口—HttpHelper

package com.haichenyi.myproject.model.http;

import io.reactivex.Flowable;

/**
* Author: 海晨忆
* Date: 2018/2/23
* Desc:网络接口,接口参数Token统一处理,方法中不传Token
*/
public interface HttpHelper {
/**
* 登录时获取验证码.
*
* @param phone 手机号
* @return {"code":0}
*/
Flowable<HttpNoResult> loginCode(String phone);
/*Flowable<HttpResult<Login>> login(String phone, String code);
Flowable<HttpResult<List<DiyBean>>> diyKeys(String allId);*/
}

 Flowable是RxJava2.0新增的,所以说RxJava完美兼容Retrofit,泛型就是我们需要解析的数据

  1. loginCode方法是说返回数据,我们只用判断是否是成功还是失败,

  2. login方法是说返回数据是一个Login对象,至于对象是什么内容,那就是和你们后台确认了

  3. diyKeys方法就是说,返回数据是一个list对象,每个list的item是DiyBean对象

package com.haichenyi.myproject.model;

import com.haichenyi.myproject.model.http.HttpHelper;
import com.haichenyi.myproject.model.http.HttpNoResult; import io.reactivex.Flowable; /**
* Author: 海晨忆
* Date: 2018/2/23
* Desc:网络请求的实现类
*/
public class DataHelper implements HttpHelper {
private HttpHelper http; public DataHelper(HttpHelper http) {
this.http = http;
} @Override
public Flowable<HttpNoResult> loginCode(String phone) {
return http.loginCode(phone);
}
}

DataHelper是HttpHelper的实现类,他的唯一作用就是调用接口的方法即可,具体的功能实现是后面一个类,这里需要说明的是这个类的构造方法要public表示,因为他要dagger生成,用private或者protected表示无法生成。

package com.haichenyi.myproject.model.http;

import com.haichenyi.myproject.model.http.api.HttpApi;

import io.reactivex.Flowable;

/**
* Author: 海晨忆
* Date: 2018/2/23
* Desc: 网络接口Retrofit实现
*/
public class RetrofitHelper implements HttpHelper{
private HttpApi httpApi; @Inject
RetrofitHelper(HttpApi httpApi) {
this.httpApi = httpApi;
} @Override
public Flowable<HttpNoResult> loginCode(String phone) {
return httpApi.loginCode(phone);
}
}

RetrofitHelper类作为HttpHelper接口的实现类,他是具体功能的实现类,为什么说他是具体功能的实现类呢?因为,他是调用HttpApi接口的方法。HttpApi接口是干什么用的呢?

package com.haichenyi.myproject.model.http.api;

import com.haichenyi.myproject.model.http.HttpNoResult;
import com.haichenyi.myproject.model.http.ProtocolHttp; import io.reactivex.Flowable;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST; /**
* Author: 海晨忆
* Date: 2018/2/23
* Desc:网络请求接口api
*/
public interface HttpApi {
/**
* 登录时获取验证码.
*
* @param phone 手机号
* @return {"code":0}
*/
@FormUrlEncoded
@POST(ProtocolHttp.METHOD_LOGIN_CODE)
Flowable<HttpNoResult> loginCode(@Field("phone") String phone);
}

这个就是Retrofit的网络请求的方式,看不懂?这个就是Retrofit的东西了
方法注解,包含@GET、@POST、@PUT、@DELETE、@PATH、@HEAD、@OPTIONS、@HTTP。
标记注解,包含@FormUrlEncoded、@Multipart、@Streaming。
参数注解,包含@Query、@QueryMap、@Body、@Field,@FieldMap、@Part,@PartMap。
其他注解,包含@Path、@Header、@Headers、@Url。

这里我们还差一个接口

package com.haichenyi.myproject.model.http;

/**
* Author: 海晨忆
* Date: 2018/2/23
* Desc:
*/
public interface ProtocolHttp {
String HTTP_HOST = "http://xxx.xx.xxx.xxx:8080/app/con/";
String HTTP_COMMON = "common/";
String METHOD_LOGIN_CODE = HTTP_COMMON + "code";//登录发送验证码
}

如上,这里需要注意的是不能以""结尾,然后就是,跟你们后台商量,格式不要错了,尽量就只有接口名字不同,接口名字前面部分都是一样的。

  到此,这里基本上就说完了,那么有同鞋就会问了,接口定义方法的时候,我们知道该如何写返回数据类型呢?这个我就不知道了,你得问你们后台,根据后台返回的数据类型去写对应的bean类。推荐一个功能PostMan。

  到目前为止,我们都还没有初始化网络请求的参数,这些网络请求的参数在哪里初始化呢?这些参数,我们就只用初始化一次,我们就想到了dagger的全局单例模式,没错,就是这个,我们上一篇写了很多没有用的东西,里面有一个HttpModule

package com.haichenyi.myproject.di.module;

import com.haichenyi.myproject.di.qualifier.ApiUrl;
import com.haichenyi.myproject.model.http.ProtocolHttp;
import com.haichenyi.myproject.model.http.api.HttpApi; import java.util.concurrent.TimeUnit; import javax.inject.Singleton; import dagger.Module;
import dagger.Provides;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory; /**
* Author: 海晨忆
* Date: 2018/2/23
* Desc:网络请求的参数初始化
*/
@Module
public class HttpModule {
@Provides
@Singleton
OkHttpClient.Builder providesOkHttpHelper() {
//请求读写超时时间
return new OkHttpClient.Builder()
.connectTimeout(, TimeUnit.SECONDS)
.readTimeout(, TimeUnit.SECONDS)
.writeTimeout(, TimeUnit.SECONDS);
} @Provides
@Singleton
OkHttpClient provideClient(OkHttpClient.Builder builder) {
return builder
// .addInterceptor(new MyHttpInterceptor())
.build();
} @Provides
@Singleton
Retrofit.Builder providesRetrofitBuilder() {
return new Retrofit.Builder();
} @Provides
@Singleton
HttpApi provideApi(@ApiUrl Retrofit retrofit) {
return retrofit.create(HttpApi.class);
} @Provides
@Singleton
@ApiUrl
Retrofit providesApiRetrofit(Retrofit.Builder builder, OkHttpClient client) {
return createRetrofit(builder, client, ProtocolHttp.HTTP_HOST);//这里就是你的网络请求的url
} private Retrofit createRetrofit(Retrofit.Builder builder, OkHttpClient client, String host) {
return builder.client(client)
.baseUrl(host)
.addConverterFactory(GsonConverterFactory.create())//添加gson自动解析,我们不用关
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}
}

如上代码,注释写的都有,考过去用就行了

在AppModule里面添加如下代码

package com.haichenyi.myproject.di.module;

import com.haichenyi.myproject.base.MyApplication;
import com.haichenyi.myproject.model.DataHelper;
import com.haichenyi.myproject.model.http.HttpHelper;
import com.haichenyi.myproject.model.http.RetrofitHelper; import javax.inject.Singleton; import dagger.Module;
import dagger.Provides; /**
* Author: 海晨忆
* Date: 2018/2/23
* Desc:
*/
@Module
public class AppModule {
private MyApplication application; public AppModule(MyApplication application) {
this.application = application;
} @Provides
@Singleton
DataHelper provideDataHelper(HttpHelper httpHelper) {
return new DataHelper(httpHelper);
} @Provides
@Singleton
HttpHelper provideHttpHelper(RetrofitHelper retrofitHelper) {
return retrofitHelper;
}
}

这里都是dagger了生成全局单例对象需要的东西

在AppComponent里面添加如下代码

package com.haichenyi.myproject.di.component;

import com.haichenyi.myproject.di.module.AppModule;
import com.haichenyi.myproject.di.module.HttpModule;
import com.haichenyi.myproject.model.DataHelper; import javax.inject.Singleton; import dagger.Component; /**
* Author: 海晨忆
* Date: 2018/2/23
* Desc:
*/
@Singleton
@Component(modules = {AppModule.class, HttpModule.class})
public interface AppComponent {
DataHelper getDataHelper();
}

在BaseMvpPresenter里面添加如下代码

package com.haichenyi.myproject.base;

import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable; /**
* Author: 海晨忆
* Date: 2018/2/23
* Desc:
*/
public class BaseMvpPresenter<T extends BaseView> implements BasePresenter<T> {
protected T baseView;
private CompositeDisposable disposables; @Override
public void attachView(T baseView) {
this.baseView = baseView;
} protected void addSubscribe(Disposable disposable) {
if (null == disposables) {
disposables = new CompositeDisposable();
}
disposables.add(disposable);
} @Override
public void detachView() {
this.baseView = null;
unSubscribe();
} private void unSubscribe() {
if (null != disposables) {
disposables.clear();
disposables = null;
}
}
}

至此,就全部写完了,关于网络请求的内容。调用方式如下:

package com.haichenyi.myproject.presenter;

import com.haichenyi.myproject.base.BaseMvpPresenter;
import com.haichenyi.myproject.base.MyApplication;
import com.haichenyi.myproject.contract.MainContract;
import com.haichenyi.myproject.model.DataHelper; import javax.inject.Inject; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers; /**
* Author: 海晨忆
* Date: 2018/2/23
* Desc:
*/
public class MainPresenter extends BaseMvpPresenter<MainContract.IView>
implements MainContract.Presenter {
private DataHelper dataHelper;
@Inject
MainPresenter() {
dataHelper = MyApplication.getAppComponent().getDataHelper();
} @Override
public void loadData() {
addSubscribe(dataHelper.loginCode("134xxxxxxxx")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe());
// baseView.showTipMsg("加载数据");
}
}

记得在清单文件里面,加上网络权限

<uses-permission android:name="android.permission.INTERNET"/>

网络请求,这样调用之后在哪处理呢?我给出我的几个处理的工具类。首先,按如下图设置1.8支持lambda表达式

 
配置.png

然后添加如下几个类

HttpCode

package com.haichenyi.myproject.model.http;

/**
* Author: 海晨忆.
* Date: 2017/12/21
* Desc: 网络请求状态码
*/
public interface HttpCode {
/**
* 成功.
*/
int SUCCESS = ;
/**
* 参数为空.
*/
int NO_PARAMETER = ;
/**
* 服务器错误.
*/
int SERVER_ERR = ;
}

ApiException

package com.haichenyi.myproject.model.http;

/**
* Author: 海晨忆.
* Date: 2017/12/21
* Desc: 接口异常判断处理
*/
public class ApiException extends Exception {
private int code; @SuppressWarnings("unused")
public ApiException(int code) {
this.code = code;
} public ApiException(int code, String message) {
super(message);
this.code = code;
} public int getCode() {
return code;
} public ApiException setCode(int code) {
this.code = code;
return this;
}
}

MyRxUtils

package com.haichenyi.myproject.model.http;

import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.FlowableTransformer;
import io.reactivex.Scheduler;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers; /**
* Author: 海晨忆.
* Date: 2017/12/27
* Desc:切换线程的工具类
*/
public class MyRxUtils {
/**
* 从其他线程转到主线程.
*
* @param scheduler Schedulers.io()等等
* @param <T> t
* @return FlowableTransformer
*/
public static <T> FlowableTransformer<T, T> toMain(Scheduler scheduler) {
return upstream -> upstream.subscribeOn(scheduler).observeOn(AndroidSchedulers.mainThread());
} public static <T> FlowableTransformer<HttpResult<T>, T> handResult() {
return upstream -> upstream.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap(tHttpResult -> {
if (tHttpResult.getCode() == HttpCode.SUCCESS) {
return /*createData(tHttpResult.data)*/Flowable.just(tHttpResult.getData());
} else {
return Flowable.error(new ApiException(tHttpResult.getCode(), tHttpResult.getMsg()));
}
});
} private static <T> Flowable<T> createData(final T data) {
return Flowable.create(e -> {
e.onNext(data);
e.onComplete();
}, BackpressureStrategy.ERROR);
}
}

MySubscriber

package com.haichenyi.myproject.model.http;

import com.haichenyi.myproject.base.BaseView;
import io.reactivex.subscribers.ResourceSubscriber; /**
* Author: 海晨忆.
* Date: 2017/12/21
* Desc:
*/
public abstract class MySubscriber<T> extends ResourceSubscriber<T> {
private BaseView baseView;
private boolean showLoading; public MySubscriber(BaseView baseView) {
this.baseView = baseView;
} public MySubscriber(BaseView baseView, boolean showLoading) {
this.baseView = baseView;
this.showLoading = showLoading;
} @Override
protected void onStart() {
super.onStart();
if (null != baseView && showLoading) {
baseView.showLoading();
}
} @Override
public void onError(Throwable t) {
if (null == baseView) {
return;
}
baseView.hideLoading();
if (t instanceof ApiException) {
ApiException apiException = (ApiException) t;
switch (apiException.getCode()) {
case HttpCode.NO_PARAMETER:
baseView.showTipMsg("参数为空");
break;
case HttpCode.SERVER_ERR:
baseView.showTipMsg("服务器错误");
break;
default:
break;
}
}
} @Override
public void onComplete() {
if (null != baseView) {
baseView.hideLoading();
}
}
}

这几个类不想多做解释,结合注释,仔细看几遍,就知道是干嘛用的了

加上这几个之后调用方式就变成了以下的方式:

package com.haichenyi.myproject.presenter;

import com.haichenyi.myproject.base.BaseMvpPresenter;
import com.haichenyi.myproject.base.MyApplication;
import com.haichenyi.myproject.contract.MainContract;
import com.haichenyi.myproject.model.DataHelper;
import com.haichenyi.myproject.model.http.HttpNoResult;
import com.haichenyi.myproject.model.http.MyRxUtils;
import com.haichenyi.myproject.model.http.MySubscriber; import javax.inject.Inject; import io.reactivex.schedulers.Schedulers; /**
* Author: 海晨忆
* Date: 2018/2/23
* Desc:
*/
public class MainPresenter extends BaseMvpPresenter<MainContract.IView>
implements MainContract.Presenter {
private DataHelper dataHelper; @Inject
MainPresenter() {
dataHelper = MyApplication.getAppComponent().getDataHelper();
} @Override
public void loadData() {
addSubscribe(dataHelper.loginCode("134xxxxxxxx")
.compose(MyRxUtils.toMain(Schedulers.io()))
.subscribeWith(new MySubscriber<HttpNoResult>(baseView, true) {
@Override
public void onNext(HttpNoResult httpNoResult) { }
}));
// baseView.showTipMsg("加载数据");
}
}

Android 从零开始搭建一个主流项目框架—RxJava2.0+Retrofit2.0+OkHttp的更多相关文章

  1. vue-用Vue-cli从零开始搭建一个Vue项目

    Vue是近两年来比较火的一个前端框架(渐进式框架吧). Vue两大核心思想:组件化和数据驱动.组件化就是将一个整体合理拆分为一个一个小块(组件),组件可重复使用:数据驱动是前端的未来发展方向,释放了对 ...

  2. 从零开始搭建一个react项目

    Nav logo 120 发现 关注 消息 4 搜索 从零开始搭建一个react项目 96 瘦人假噜噜 2017.04.23 23:29* 字数 6330 阅读 32892评论 31喜欢 36 项目地 ...

  3. 手把手教你从零开始搭建SpringBoot后端项目框架

    原料 新鲜的IntelliJ IDEA.一双手.以及电脑一台. 搭建框架 新建项目 打开IDE,点击File -> New Project.在左侧的列表中的选择Maven项目,点击Next. 填 ...

  4. 搭建一个SSH项目框架的步骤

    1.导入jar包(38个) 2.配置文件 applicationContext,xml (beans.xml) (数据源.LocalSessionFactoryBean.事务管理器.事务通知.AOP切 ...

  5. 从零开始搭建一个PaaS平台 - 我们要做什么

    前言 从最开始的小公司做小网站,到现在进入现在的公司做项目,发现小公司里很多很多工作都是重复的劳动(增删改查),不过想想也是,业务软件最基础的东西不就是增删改查吗. 但是很多时候,这种业务逻辑其实没有 ...

  6. Github+yeoman+gulp-angular初始化搭建angularjs前端项目框架

    在上篇文章里面我们说到了Github账号的申请与配置 那么当你有了Github账号并创建了一个自己的Github项目之后,首要的当然是搭建自己的项目框架啦! 本人对自己的定位是web前端狗,常用开发框 ...

  7. 从零开始搭建一个简单的基于webpack的vue开发环境

    原文地址:https://segmentfault.com/a/1190000012789253?utm_source=tag-newest 从零开始搭建一个简单的基于webpack的react开发环 ...

  8. 基于 Express 搭建一个node项目 - 起步

    一,如何基于 Express 搭建一个node项目 什么是Express 借用官方的介绍,Express是一个基于Node.js平台的极简.灵活的web应用开发框架,它提供了一系列强大的特性,帮助你创 ...

  9. 完整搭建一个vue项目

    目录 一. 搭建一个vue项目的完整步骤 二. 卸载vue-cli 三. 完全卸载webpack 一. 搭建一个vue项目的完整步骤 1.安装node.js 下载地址 # 检查是否安装成功 node ...

随机推荐

  1. Statement, PreparedStatement和CallableStatement的区别

    Statement用于执行不带参数的简单SQL语句,并返回它所生成的结果,每次执行SQL豫剧时,数据库都要编译该SQL语句. Satatement stmt = conn.getStatement() ...

  2. es6基础系列三:解构赋值

    解构就是ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值(只能用于数组,对象或迭代器).如果解构不成功,则等于undefined,但不能赋值为undefined和null,因为undefi ...

  3. JS中的参数搜寻机制

    1: var color="blue"; function changecolor(color){ if(color=="blue"){ color=" ...

  4. [Xcode 实际操作]四、常用控件-(17)为MKMapView地图上显示提示框

    目录:[Swift]Xcode实际操作 本文将演示当点击地图上的标注圆点时,弹出信息窗口. 在项目导航区,打开视图控制器的代码文件[ViewController.swift] import UIKit ...

  5. Java Web之分页的实现(通用)

    一.用到的工具类的封装 为了实现代码的重用性,我们将经常用到的代码封装到工具类中,以便在任何地方都可以调用 1.获取路径工具 在jsp页面中,我们经常会向Servlet发送请求,并通过反射,实现通过传 ...

  6. 从输入URL到浏览器显示页面

    去看经典是不会错的,如果觉得太长,那就休息一下继续看. 经验告诉我,读一篇经典足矣,不要浪费时间去搜索其他地方到处复制粘贴的博文. 所以奉上我过滤的经典: 1.How browser work 2.h ...

  7. Java安装及配置开发环境

    这篇文章里将记录安装Java及配置Java环境的一些步骤,以及基于Java的可扩展开发平台Eclipse的Android开发环境的配置. 准备工具 1.JDK下载 下载地址 关于左侧列栏的Java S ...

  8. selenium框架安装及webdriver安装

    本文介绍的是selenium安装及webdriver安装.小实例 1.selenium介绍 selenium是一个用于web应用程序测试的工具. Selenium测试直接运行在浏览器,就向真正的用户操 ...

  9. Telerik RadPropertyGrid 设置显隐 Combox选择

    Telerik RadPropertyGrid 的排序按钮.搜索框和描述面板的显隐只要设置SortAndGroupButtons.SearchBox.DescriptionPanel的属性值改为Vis ...

  10. windows 7 elasticsearch-5.3.2

    # windows elasticsearch- D:\nescafe\elasticsearch-\bin λ java -version java version "1.8.0_121& ...