开发android项目时,经常遇到这样的需求,在请求网络的时候,一个网络请求可能会建立在另一个网络请求基础上进行,例如:做一个省市县联动的需求,假设接口给我们的数据是分级查询,我们直接要查询县,可能就先要查询省,然后返回省之后再调用查询市的接口查询出城市,再在城市查询成功后调用查询县的接口,在代码中,我们可能会这样写(网络请求使用okHttp):
public void getData(){
//查询省
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().get().url("http://www.baidu.com/").build();
Call call = client.newCall(request);
//查询省
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//失败
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
final String responseStr = response.body().string();
//成功
//查询到省
//构建查询市的请求
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().get().url("http://www.baidu.com/").build();
Call call1 = client.newCall(request);
//查询市
call1.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//失败
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
final String responseStr = response.body().string();
//成功
//查询到市
//构建查询县的请求
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().get().url("http://www.baidu.com/").build();
Call call1 = client.newCall(request);
//查询县
call1.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//失败
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
final String responseStr = response.body().string();
//成功
//查询到县
}
});
}
});
}
});
}
上面这段代码是不是看上去非常的繁琐?可能您有更好的写法,但是都逃不过回调成功后嵌套执行的命运。嵌套越多越容易出错。所以基于这样一个需求,我设计出了一个代码模式,可以顺序的执行代码块,而且使用起来非常的简单。
请看下面的调用代码示例:
public void getData1(){
QueueEventCode.getInstance().enqueue(new OnCodeEvent() {
@Override
protected void onDoingCode(Bundle b) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().get().url("http://www.baidu.com/").build();
Call call1 = client.newCall(request);
//查询省
call1.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//失败
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
final String responseStr = response.body().string();
//成功
//查询到省
Bundle bundle=new Bundle();
bundle.putString("key",responseStr);
QueueEventCode.getInstance().next(bundle);//通知下次请求开始,并传递参数
}
});
}
}).enqueue(new OnCodeEvent() {
@Override
protected void onDoingCode(Bundle b) {//可以从bundle中取出上一次回调来的参数,上一次返回的是省
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().get().url("http://www.baidu.com/").build();
Call call1 = client.newCall(request);
//查询市
call1.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//失败
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
final String responseStr = response.body().string();
//成功
//查询到市
Bundle bundle=new Bundle();
bundle.putString("key",responseStr);
QueueEventCode.getInstance().next(bundle);//通知下次请求开始,并传递参数
}
});
}
}).enqueue(new OnCodeEvent() {
@Override
protected void onDoingCode(Bundle b) {//可以从bundle中取出上一次回调来的参数,上一次返回的是市
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().get().url("http://www.baidu.com/").build();
Call call1 = client.newCall(request);
//查询市
call1.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//失败
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
final String responseStr = response.body().string();
//成功
//查询到县
Bundle bundle=new Bundle();
bundle.putString("key",responseStr);
QueueEventCode.getInstance().next(bundle);//通知下次请求开始,并传递参数
}
});
}
});
}
看上去上面的代码量比之前的代码量还多,但是逻辑却清晰很多,有时候代码的维护可比代码量更重要。主要的逻辑是获取QueueEvent的单例,调用enqueue方法把代码块设置进queue队列,queue队列实现了一个while循环调用取队列里面的代码块并执行,在执行完成后调用next方法通知进行下一次调用,next可以传值也可以不传,调用next传的值会回调给下一次调用的回调方法onDoingCode方法传递,也可以调用父类的onDoneCode方法单独处理本次回调过来的值。QueueEventCode是QueueEvent的子类,核心代码主要在QueueEvent中:
public abstract class QueueEvent<T,T1 extends QueueEvent> {
public static final String TAG = "QueueEvent";
/**
* 线程执行频率,值越高,间隔时间越长,单位毫秒
*/
private int seeped = 1000;
/**
* 对象锁
*/
private Object lock = new Object();
/**
* 线程列队
*/
private Queue<T> tQueue = new LinkedList<>();
/**
* 是否正在运行
*/
private boolean running = false;
private T t;
protected abstract T1 getQueueEventChildInstance();
protected abstract void onQueueEventDoing(T t);
protected abstract void finishChild();
protected void onQueueEventDone(Bundle b,T t){};
/**
* 添加单个线程
*
* @param t
*/
public T1 enqueue(T t) {
if (!tQueue.contains(t)) {
tQueue.add(t);
}
start();
return getQueueEventChildInstance();
}
/**
* 添加多个线程
*
* @param ts
* @return
*/
public T1 enqueue(LinkedList<T> ts) {
for (T t : ts) {
if (!tQueue.contains(t)) {
tQueue.add(t);
}
}
start();
return getQueueEventChildInstance();
}
/**
* 停止运行,不再使用的时候需要主动调用
*/
public void finish() {
running = false;
Log.i(TAG, "任务主线程循环停止");
finishChild();
}
/**
* 开始运行
*/
private void start() {
if (!running) {
running = true;
new Thread() {
@Override
public void run() {
while (running) {
synchronized (lock) {
t = tQueue.poll();
if (t != null) {
Log.i(TAG, "开始执行任务");
onQueueEventDoing(t);
try {
//暂停线程
lock.wait();
Log.i(TAG, "主线程等待中...");
} catch (Exception e) {
e.printStackTrace();
}
}
try {
//控制刷新速率
sleep(getSeeped());
} catch (Exception e) {
e.printStackTrace();
}
Log.i(TAG,"剩余总任务数:"+tQueue.size());
Log.i(TAG, "任务主线程执行...");
}
}
}
}.start();
}
}
public void next(){
this.next(null);
}
/**
* 运行下一个线程
*/
public void next(Bundle b) {
Log.i(TAG, "任务主线程执行下一个...");
if(b!=null) {
onQueueEventDone(b,t);
}
new Thread() {
@Override
public void run() {
synchronized (lock){
//执行线程
lock.notify();
}
}
}.start();
}
private int getSeeped() {
return seeped;
}
public T1 setSeeped(int seeped) {
this.seeped = seeped;
return getQueueEventChildInstance();
}
}
代码我就不贴全部的了,主要是看思想,欢迎指正。