<!-- 联网权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 访问网络状态 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />-
Android 9.0 限制了明文流量的网络请求,非加密的流量请求都会被系统禁止掉。 如果当前应用的请求是 http 请求,而非 https ,这样就会导系统禁止当前应用进行该请求,如果 WebView 的 url 用 http 协议,同样会出现加载失败,https 不受影响
-
在 res 下新建一个 xml 目录,然后创建一个名为:
network_security_config.xml文件 ,该文件内容如下
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>- 然后在 AndroidManifest.xml application 标签内应用上面的xml配置
<application
android:networkSecurityConfig="@xml/network_security_config" />public class RequestServer implements IRequestServer {
@Override
public String getHost() {
return "https://www.baidu.com/";
}
@Override
public String getPath() {
return "api/";
}
@Override
public BodyType getType() {
// 参数以 Json 格式提交(默认是表单)
return BodyType.JSON;
}
}- 需要配置请求结果处理,具体封装可以参考 RequestHandler
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.build();
EasyConfig.with(okHttpClient)
// 是否打印日志
.setLogEnabled(BuildConfig.DEBUG)
// 设置服务器配置
.setServer(server)
// 设置请求处理策略
.setHandler(new RequestHandler())
// 设置请求重试次数
.setRetryCount(3)
// 添加全局请求参数
//.addParam("token", "6666666")
// 添加全局请求头
//.addHeader("time", "20191030")
// 启用配置
.into();- 上述是创建配置,更新配置可以使用
EasyConfig.getInstance()
.addParam("token", data.getData().getToken());# OkHttp3
-keepattributes Signature
-keepattributes *Annotation*
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okhttp3.**
-dontwarn okio.**
# 不混淆这个包下的类
-keep class com.xxx.xxx.xxx.xxx.** {
<fields>;
}public final class LoginApi implements IRequestApi {
@Override
public String getApi() {
return "user/login";
}
/** 用户名 */
private String userName;
/** 登录密码 */
private String password;
public LoginApi setUserName(String userName) {
this.userName = userName;
return this;
}
public LoginApi setPassword(String password) {
this.password = password;
return this;
}
}-
可为这个类的字段加上一些注解
-
@HttpHeader:标记这个字段是一个请求头参数
-
@HttpIgnore:标记这个字段不会被发送给后台
-
@HttpRename:重新定义这个字段发送给后台的参数名称
-
-
可在这个类实现一些接口
-
implements IRequestHost:实现这个接口之后可以重新指定这个请求的主机地址
-
implements IRequestPath:实现这个接口之后可以重新指定这个请求的接口路径
-
implements IRequestType:实现这个接口之后可以重新指定这个请求的提交方式
-
implements IRequestCache:实现这个接口之后可以重新指定这个请求的缓存模式
-
implements IRequestClient:实现这个接口之后可以重新指定这个请求所用的 OkHttpClient 对象
-
-
字段作为请求参数的衡量标准
-
假设某个字段的属性值为空,那么这个字段将不会作为请求参数发送给后台
-
假设果某个字段类型是 String,属性值是空字符串,那么这个字段就会作为请求参数,如果是空对象则不会
-
假设某个字段类型是 int,因为基本数据类型没有空值,所以这个字段一定会作为请求参数,但是可以换成 Integer 对象来避免,因为 Integer 的默认值是 null
-
-
getHost、getPath、getApi 方法之间的作用和区别?
-
Host:主机地址
-
Path:模块地址
-
Api:业务地址
-
-
我举个栗子:https://www.baidu.com/api/user/getInfo,那么标准的写法就是
public final class XxxApi implements IRequestServer, IRequestApi {
@Override
public String getHost() {
return "https://www.baidu.com/";
}
@Override
public String getPath() {
return "api/";
}
@Override
public String getApi() {
return "user/getInfo";
}
}- 需要配置请求状态及生命周期处理,具体封装可以参考 BaseActivity
EasyHttp.post(this)
.api(new LoginApi()
.setUserName("Android 轮子哥")
.setPassword("123456"))
.request(new HttpCallback<HttpData<LoginBean>>(activity) {
@Override
public void onSucceed(HttpData<LoginBean> data) {
ToastUtils.show("登录成功");
}
});- 这里展示 post 用法,另外 EasyHttp 还支持 get、head、delete、put、patch 请求方式,这里不再过多演示
public final class UpdateImageApi implements IRequestApi, IRequestType {
@Override
public String getApi() {
return "upload/";
}
@Override
public BodyType getType() {
// 上传文件需要使用表单的形式提交
return BodyType.FORM;
}
/** 本地图片 */
private File image;
public UpdateImageApi(File image) {
this.image = image;
}
public UpdateImageApi setImage(File image) {
this.image = image;
return this;
}
}EasyHttp.post(this)
.api(new UpdateImageApi(file))
.request(new OnUpdateListener<Void>() {
@Override
public void onStart(Call call) {
mProgressBar.setVisibility(View.VISIBLE);
}
@Override
public void onProgress(int progress) {
mProgressBar.setProgress(progress);
}
@Override
public void onSucceed(Void result) {
ToastUtils.show("上传成功");
}
@Override
public void onFail(Exception e) {
ToastUtils.show("上传失败");
}
@Override
public void onEnd(Call call) {
mProgressBar.setVisibility(View.GONE);
}
});- 需要注意的是:如果上传的文件过多或者过大,可能会导致请求超时,可以重新设置本次请求超时时间,超时时间建议根据文件大小而定,具体设置超时方式文档有介绍,可以在本页面直接搜索。
- 下载缓存策略:在指定下载文件 md5 或者后台有返回 md5 的情况下,下载框架默认开启下载缓存模式,如果这个文件已经存在手机中,并且经过 md5 校验文件完整,框架就不会重复下载,而是直接回调下载监听。减轻服务器压力,减少用户等待时间。
EasyHttp.download(this)
.method(HttpMethod.GET)
.file(new File(Environment.getExternalStorageDirectory(), "微信.apk"))
//.url("https://qd.myapp.com/myapp/qqteam/AndroidQQ/mobileqq_android.apk")
.url("http://dldir1.qq.com/weixin/android/weixin708android1540.apk")
.md5("2E8BDD7686474A7BC4A51ADC3667CABF")
.listener(new OnDownloadListener() {
@Override
public void onStart(File file) {
mProgressBar.setVisibility(View.VISIBLE);
}
@Override
public void onProgress(File file, int progress) {
mProgressBar.setProgress(progress);
}
@Override
public void onComplete(File file) {
ToastUtils.show("下载完成:" + file.getPath());
installApk(MainActivity.this, file);
}
@Override
public void onError(File file, Exception e) {
ToastUtils.show("下载出错:" + e.getMessage());
}
@Override
public void onEnd(File file) {
mProgressBar.setVisibility(View.GONE);
}
}).start();try {
HttpData<SearchBean> data = EasyHttp.post(MainActivity.this)
.api(new SearchBlogsApi()
.setKeyword("搬砖不再有"))
.execute(new ResponseClass<HttpData<SearchBean>>() {});
ToastUtils.show("请求成功,请看日志");
} catch (Exception e) {
e.printStackTrace();
ToastUtils.show(e.getMessage());
}- 需要先实现读取和写入缓存的接口,如果已配置则可以跳过,这里以 MMKV 为例
public final class RequestHandler implements IRequestHandler {
private final Application mApplication;
private final MMKV mMmkv;
public RequestHandler(Application application) {
mApplication = application;
mMmkv = MMKV.mmkvWithID("http_cache_id");
}
..................
@Override
public Object readCache(LifecycleOwner lifecycle, IRequestApi api, Type type) {
String cacheKey = GsonFactory.getSingletonGson().toJson(api);
String cacheValue = mMmkv.getString(cacheKey, null);
if (cacheValue == null || "".equals(cacheValue) || "{}".equals(cacheValue)) {
return null;
}
EasyLog.print("---------- cacheKey ----------");
EasyLog.json(cacheKey);
EasyLog.print("---------- cacheValue ----------");
EasyLog.json(cacheValue);
return GsonFactory.getSingletonGson().fromJson(cacheValue, type);
}
@Override
public boolean writeCache(LifecycleOwner lifecycle, IRequestApi api, Response response, Object result) {
String cacheKey = GsonFactory.getSingletonGson().toJson(api);
String cacheValue = GsonFactory.getSingletonGson().toJson(result);
if (cacheValue == null || "".equals(cacheValue) || "{}".equals(cacheValue)) {
return false;
}
EasyLog.print("---------- cacheKey ----------");
EasyLog.json(cacheKey);
EasyLog.print("---------- cacheValue ----------");
EasyLog.json(cacheValue);
return mMmkv.putString(cacheKey, cacheValue).commit();
}
}- 首先请求缓存模式有四种方式,都在
CacheMode这个枚举类中
public enum CacheMode {
/**
* 默认(按照 Http 协议来缓存)
*/
DEFAULT,
/**
* 不使用缓存(禁用 Http 协议缓存)
*/
NO_CACHE,
/**
* 只使用缓存
*
* 有缓存的情况下:读取缓存 -> 回调成功
* 无缓存的情况下:请求网络 -> 写入缓存 -> 回调成功
*/
USE_CACHE_ONLY,
/**
* 优先使用缓存
*
* 有缓存的情况下:先读缓存 —> 回调成功 —> 请求网络 —> 刷新缓存
* 无缓存的情况下:请求网络 -> 写入缓存 -> 回调成功
*/
USE_CACHE_FIRST,
/**
* 只在网络请求失败才去读缓存
*/
USE_CACHE_AFTER_FAILURE
}- 为某个接口设置缓存模式
public final class XxxApi implements IRequestApi, IRequestCache {
@Override
public String getApi() {
return "xxx/";
}
@Override
public CacheMode getMode() {
// 设置优先使用缓存
return CacheMode.USE_CACHE_FIRST;
}
}- 全局设置缓存模式
public class XxxServer implements IRequestServer {
@Override
public String getHost() {
return "https://www.xxxxxxx.com/";
}
@Override
public CacheMode getMode() {
// 只在请求失败才去读缓存
return CacheMode.USE_CACHE_AFTER_FAILURE;
}
}// 添加全局请求参数
EasyConfig.getInstance().addParam("token", "abc");
// 添加全局请求头
EasyConfig.getInstance().addHeader("token", "abc");EasyConfig.getInstance().setInterceptor(new IRequestInterceptor() {
@Override
public void interceptArguments(IRequestApi api, HttpParams params, HttpHeaders headers) {
headers.put("timestamp", String.valueOf(System.currentTimeMillis()));
}
});public final class XxxApi implements IRequestApi {
@Override
public String getApi() {
return "xxx/xxxx";
}
@HttpIgnore
private String token;
}IRequestServer server = EasyConfig.getInstance().getServer();
// 获取当前全局的服务器主机地址
String host = server.getHost();
// 获取当前全局的服务器路径地址
String path = server.getPath();- 先定义一个服务器配置
public class XxxServer implements IRequestServer {
@Override
public String getHost() {
return "https://www.xxxxxxx.com/";
}
@Override
public String getPath() {
return "api/";
}
}- 再将它应用到全局配置中
EasyConfig.getInstance().setServer(new XxxServer());- 如果只是针对某个接口可以这样配置
public final class XxxApi extends XxxServer implements IRequestApi {
@Override
public String getApi() {
return "xxx/xxxx";
}
}- 如果不想单独定义一个类,也可以这样写
public final class XxxApi implements IRequestServer, IRequestApi {
@Override
public String getHost() {
return "https://www.xxxxxxx.com/";
}
@Override
public String getPath() {
return "api/";
}
@Override
public String getApi() {
return "xxx/xxxx";
}
}- 先定义一个普通接口的测试服和正式服的配置
public class TestServer implements IRequestServer {
@Override
public String getHost() {
return "https://www.test.xxxxxxx.com/";
}
@Override
public String getPath() {
return "api/";
}
}public class ReleaseServer implements IRequestServer {
@Override
public String getHost() {
return "https://www.xxxxxxx.com/";
}
@Override
public String getPath() {
return "api/";
}
}- 再将它应用到全局配置中
IRequestServer server;
if (BuildConfig.DEBUG) {
server = new TestServer();
} else {
server = new ReleaseServer();
}
EasyConfig.getInstance().setServer(server);- 假设要为 H5 业务模块设定特定服务器配置,可以这样做
public class H5Server implements IRequestServer {
@Override
public String getHost() {
IRequestServer server = EasyConfig.getInstance().getServer();
if (server instanceof TestServer) {
return "https://www.test.h5.xxxxxxx.com/";
}
return "https://www.h5.xxxxxxx.com/";
}
@Override
public String getPath() {
return "api/";
}
}- 在配置接口的时候继承 H5Server 就可以了,其他 H5 模块的配置也是雷同
public final class UserAgreementApi extends H5Server implements IRequestApi {
@Override
public String getApi() {
return "user/agreement";
}
}- 以表单的形式提交参数(默认)
public class XxxServer implements IRequestServer {
@Override
public String getHost() {
return "https://www.xxxxxxx.com/";
}
@Override
public String getPath() {
return "api/";
}
@Override
public BodyType getType() {
return BodyType.FORM;
}
}- 以 Json 的形式提交参数
public class XxxServer implements IRequestServer {
@Override
public String getHost() {
return "https://www.xxxxxxx.com/";
}
@Override
public String getPath() {
return "api/";
}
@Override
public BodyType getType() {
return BodyType.JSON;
}
}- 当然也支持对某个接口进行单独配置
public final class XxxApi implements IRequestApi, IRequestType {
@Override
public String getApi() {
return "xxx/xxxx";
}
@Override
public BodyType getType() {
return BodyType.JSON;
}
}- 表单和 Json 方式提交的优缺点对比
- 这块的需求比较奇葩,但是搭配 OkHttp 拦截器仍然是可以实现的,这得益于 EasyHttp 良好的框架设计
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
RequestBody body = request.body();
if (body instanceof JsonBody) {
body = new JsonBody("假装加密了:" + ((JsonBody) body).getJson());
Request.Builder builder = request.newBuilder();
builder.method(request.method(), body);
request = builder.build();
}
return chain.proceed(request);
}
})
.build();- 在 Application 初始化 EasyHttp 的时候配置进去
EasyConfig.with(okHttpClient)
//.setXxxx(Xxxx)
//.setXxxx(Xxxx)
//.setXxxx(Xxxx)
.into();public final class XxxApi implements IRequestApi {
@Override
public String getApi() {
return "xxx/xxxx";
}
@HttpIgnore
private String address;
}public final class XxxApi implements IRequestApi {
@Override
public String getApi() {
return "xxx/xxxx";
}
@HttpHeader
private String time;
}public final class XxxApi implements IRequestApi {
@Override
public String getApi() {
return "xxx/xxxx";
}
@HttpRename("k")
private String keyword;
}- 使用 File 对象上传
public final class XxxApi implements IRequestApi {
@Override
public String getApi() {
return "xxx/xxxx";
}
private File file;
}- 使用 InputStream 对象上传
public final class XxxApi implements IRequestApi {
@Override
public String getApi() {
return "xxx/xxxx";
}
private InputStream inputStream;
}- 使用 RequestBody 对象上传
public final class XxxApi implements IRequestApi {
@Override
public String getApi() {
return "xxx/xxxx";
}
private RequestBody requestBody;
}public final class XxxApi implements IRequestApi {
@Override
public String getApi() {
return "xxx/xxxx";
}
private List<File> files;
}// 设置请求重试次数
EasyConfig.getInstance().setRetryCount(3);
// 设置请求重试时间
EasyConfig.getInstance().setRetryTime(1000);- 全局配置(针对所有接口都生效)
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.readTimeout(5000, TimeUnit.MILLISECONDS);
builder.writeTimeout(5000, TimeUnit.MILLISECONDS);
builder.connectTimeout(5000, TimeUnit.MILLISECONDS);
EasyConfig.with(builder.build())
.into();- 局部配置(只在某个接口上生效)
public final class XxxApi implements IRequestApi, IRequestClient {
@Override
public String getApi() {
return "xxxx/";
}
@Override
public OkHttpClient getClient() {
OkHttpClient.Builder builder = EasyConfig.getInstance().getClient().newBuilder();
builder.readTimeout(5000, TimeUnit.MILLISECONDS);
builder.writeTimeout(5000, TimeUnit.MILLISECONDS);
builder.connectTimeout(5000, TimeUnit.MILLISECONDS);
return builder.build();
}
}EasyConfig.getInstance().setLogEnabled(false);// 取消和这个 LifecycleOwner 关联的请求
EasyHttp.cancel(LifecycleOwner lifecycleOwner);
// 取消指定 Tag 标记的请求
EasyHttp.cancel(Object tag);
// 取消所有请求
EasyHttp.cancel();EasyHttp.post(MainActivity.this)
.api(new XxxApi())
// 延迟 5 秒后请求
.delay(5000)
.request(new HttpCallback<HttpData<XxxBean>>(MainActivity.this) {
@Override
public void onSucceed(HttpData<XxxBean> result) {
}
});- 关于这个问题,其实可以利用框架中提供的 IRequestHandler 接口,在 requestStart 方法中对 Request 对象进行加密,而在 requestSucceed 方法中对 Response 对象解密,然后在 EasyHttp 初始化的时候将 IRequestHandler 实现对象传入给框架即可。
public interface IRequestHandler {
/**
* 请求开始
*/
default Request requestStart(LifecycleOwner lifecycle, IRequestApi api, Request request) {
return request;
}
/**
* 请求成功时回调
*/
Object requestSucceed(LifecycleOwner lifecycle, IRequestApi api, Response response, Type type) throws Exception;
/**
* 请求失败
*/
Exception requestFail(LifecycleOwner lifecycle, IRequestApi api, Exception e);
}- 如果你想对某个接口进行加解密,可以根据方法中的 api 参数对象来判断 ,如果你想对部分接口进行加解密,可以让外层的 IRequestApi 类实现统一的接口来标识这些接口,然后在 requestStart 和 requestFail 方法中判断 api 参数对象是否实现了这个接口来决定要不要进行加解密。
public final class XxxApi implements IRequestApi {
@Override
public String getApi() {
return "article/query/" + pageNumber + "/json";
}
@HttpIgnore
private int pageNumber;
public XxxApi setPageNumber(int pageNumber) {
this.pageNumber = pageNumber;
return this;
}
}- 在初始化 OkHttp 的时候这样设置
HttpSslConfig sslConfig = HttpSslFactory.generateSslConfig();
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.sslSocketFactory(sslConfig.getsSLSocketFactory(), sslConfig.getTrustManager())
.hostnameVerifier(HttpSslFactory.generateUnSafeHostnameVerifier())
.build();-
但是不推荐这样做,因为这样是不安全的,意味着每个请求都不会用 Https 去校验
-
当然框架中也提供了一些生成的证书的 API,具体请参见 com.hjq.http.ssl 包下的类
- 先定义一个 URL 管理类,将 URL 配置到这个类中
public final class HttpUrls {
/** 获取用户信息 */
public static final String GET_USER_INFO = "user/getUserInfo";
}- 然后在 EasyHttp 引入接口路径
EasyHttp.post(this)
.api(HttpUrls.GET_USER_INFO)
.request(new HttpCallback<HttpData<XxxBean>>(this) {
@Override
public void onSucceed(HttpData<XxxBean> result) {
}
});-
不过这种方式只能应用于没有参数的接口,有参数的接口还是需要写一个类,因为框架只会在 Api 类中去解析参数。
-
虽然 EasyHttp 开放了这种写法,但是身为作者的我并不推荐你这样写,因为这样写会导致扩展性很差,比如后续加参数,还要再改回来,并且无法对接口进行动态化配置。
-
其中 AndroidX.AppCompatActivity 和 AndroidX.Fragment 都是 LifecycleOwner 子类的,这个是毋庸置疑的
-
但是你如果传入的是 Activity 对象,并非 AppCompatActivity 对象,那么你可以这样写
EasyHttp.post(new ActivityLifecycle(this))
.api(new XxxApi())
.request(new HttpCallback<HttpData<XxxBean>>(this) {
@Override
public void onSucceed(HttpData<XxxBean> result) {
}
});- 你如果想在 Service 中使用 EasyHttp,请将 Service 直接继承框架中的 LifecycleService 类,又或者在项目中封装一个带有 Lifecycle 特性的 Service 基类,具体实现如下:
public abstract class LifecycleService extends Service implements LifecycleOwner {
private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
@NonNull
@Override
public Lifecycle getLifecycle() {
return mLifecycle;
}
@Override
public void onCreate() {
super.onCreate();
mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
}
@Override
public void onDestroy() {
super.onDestroy();
mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
}
}- 如果以上条件都不满足,但是你就是想在某个地方请求网络,那么你可以这样写
EasyHttp.post(new ApplicationLifecycle())
.api(new XxxApi())
.tag("abc")
.request(new OnHttpListener<HttpData<XxxBean>>() {
@Override
public void onSucceed(HttpData<XxxBean> result) {
}
@Override
public void onFail(Exception e) {
}
});-
需要注意的是,传入 ApplicationLifecycle 将意味着框架无法自动把控请求的生命周期,如果在 Application 中这样写是完全可以的,但是不能在 Activity 或者 Service 中这样写,因为这样可能会导致内存泄漏。
-
除了 Application,如果你在 Activity 或者 Service 中采用了 ApplicationLifecycle 的写法,那么为了避免内存泄漏或者崩溃的事情发生,需要你在请求的时候设置对应的 Tag,然后在恰当的时机手动取消请求(一般在 Activity 或者 Service 销毁或者退出的时候取消请求)。
EasyHttp.cancel("abc");-
首先这个加载对话框不是框架自带的,是可以修改或者取消的,主要有两种方式可供选择
-
第一种方式:重写 HttpCallback 类方法
EasyHttp.post(this)
.api(new XxxApi())
.request(new HttpCallback<Xxx>(this) {
@Override
public void onStart(Call call) {
// 重写方法并注释父类调用
//super.onStart(call);
}
@Override
public void onEnd(Call call) {
// 重写方法并注释父类调用
//super.onEnd(call);
}
});- 第二种方式:直接实现 OnHttpListener 接口
EasyHttp.post(this)
.api(new XxxApi())
.request(new OnHttpListener<Xxx>() {
@Override
public void onSucceed(Xxx result) {
}
@Override
public void onFail(Exception e) {
}
});- 添加远程依赖
dependencies {
// RxJava:https://github.com/ReactiveX/RxJava
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
implementation 'io.reactivex.rxjava2:rxjava:2.2.12'
}- 请注意 RxJava 需要自行处理生命周期,以免发生内存泄漏
Observable.create(new ObservableOnSubscribe<HttpData<SearchBean>>() {
@Override
public void subscribe(ObservableEmitter<HttpData<SearchBean>> emitter) throws Exception {
HttpData<SearchBean> data1;
try {
data1 = EasyHttp.post(MainActivity.this)
.api(new SearchBlogsApi()
.setKeyword("搬砖不再有"))
.execute(new ResponseClass<HttpData<SearchBean>>() {});
} catch (Exception e) {
e.printStackTrace();
ToastUtils.show(e.getMessage());
throw e;
}
HttpData<SearchBean> data2;
try {
data2 = EasyHttp.post(MainActivity.this)
.api(new SearchBlogsApi()
.setKeyword(data1.getMessage()))
.execute(new ResponseClass<HttpData<SearchBean>>() {});
} catch (Exception e) {
e.printStackTrace();
ToastUtils.show(e.getMessage());
throw e;
}
emitter.onNext(data2);
emitter.onComplete();
}
})
// 让被观察者执行在IO线程
.subscribeOn(Schedulers.io())
// 让观察者执行在主线程
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<HttpData<SearchBean>>() {
@Override
public void accept(HttpData<SearchBean> data) throws Exception {
Log.d("EasyHttp", "最终结果为:" + data.getMessage());
}
});Observable.create(new ObservableOnSubscribe<IRequestApi>() {
@Override
public void subscribe(ObservableEmitter<IRequestApi> emitter) throws Exception {
SearchBlogsApi api1 = new SearchBlogsApi()
.setKeyword("1");
SearchBlogsApi api2 = new SearchBlogsApi()
.setKeyword("2");
emitter.onNext(api1);
emitter.onNext(api2);
emitter.onComplete();
}
})
.map(new Function<IRequestApi, HttpData<Void>>() {
@Override
public HttpData<Void> apply(IRequestApi api) throws Exception {
try {
return EasyHttp.post(MainActivity.this)
.api(api)
.execute(new ResponseClass<HttpData<Void>>() {});
} catch (Exception e) {
e.printStackTrace();
ToastUtils.show(e.getMessage());
throw e;
}
}
})
// 让被观察者执行在 IO 线程
.subscribeOn(Schedulers.io())
// 让观察者执行在主线程
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<HttpData<Void>>() {
@Override
public void accept(HttpData<Void> data) throws Exception {
Log.d("EasyHttp", "最终结果为:" + data.getMessage());
}
});// 发起轮询请求,共发起三次请求,第一次请求在 5 秒后触发,剩下两次在 1 秒 和 2 秒后触发
Observable.intervalRange(1, 3, 5000, 1000, TimeUnit.MILLISECONDS)
// 让被观察者执行在 IO 线程
.subscribeOn(Schedulers.io())
// 让观察者执行在主线程
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Long>() {
@Override
public void accept(Long aLong) throws Exception {
EasyHttp.post(MainActivity.this)
.api(new SearchBlogsApi()
.setKeyword("搬砖不再有"))
.request(new HttpCallback<HttpData<SearchBean>>(MainActivity.this) {
@Override
public void onSucceed(HttpData<SearchBean> result) {
}
});
}
});Observable.create(new ObservableOnSubscribe<HttpData<SearchBean>>() {
@Override
public void subscribe(ObservableEmitter<HttpData<SearchBean>> emitter) throws Exception {
EasyHttp.post(MainActivity.this)
.api(new SearchBlogsApi()
.setKeyword("搬砖不再有"))
.request(new HttpCallback<HttpData<SearchBean>>(MainActivity.this) {
@Override
public void onSucceed(HttpData<SearchBean> result) {
emitter.onNext(result);
emitter.onComplete();
}
@Override
public void onFail(Exception e) {
super.onFail(e);
emitter.onError(e);
}
});
}
})
.map(new Function<HttpData<SearchBean>, String>() {
@Override
public String apply(HttpData<SearchBean> data) throws Exception {
int curPage = data.getData().getCurPage();
int pageCount = data.getData().getPageCount();
return curPage + "/" + pageCount;
}
})
// 让被观察者执行在 IO 线程
.subscribeOn(Schedulers.io())
// 让观察者执行在主线程
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.d("EasyHttp", ""当前页码位置" + s);
}
});