队列执行线程和代码

开发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();
    }
}

代码我就不贴全部的了,主要是看思想,欢迎指正。

源码下载GitHub

源码下载CSDN

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

许天成

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值