RxJava или Java 8 Stream хорошо подходит для таких задач. Лучше RxJava, так как умеет в многопоток. Оба API созданы для удобной работы с входными потоками. API OkHttp не знаю, ибо не писал клиентов магазинов и типичного. Вот туториал:
https://www.vogella.com/tutorials/RxJava/article.html
А вообще, если хочется простого, делаете очередь, что-то типа:
public class Result {
public final static int NEXT = 1;
public final static int FINISH = 2;
public final static int ERROR = 3;
public final static int NO_NEXT = 4;
public final int result;
public final String someData;
public final Throwable tr;
public Result(int result, String someData, Throwable tr) {
this.result = result;
this.someData = someData;
this.tr = tr;
}
}
public abstract class Operation {
final Queue queue;
public Operation(Queue queue) {
this.queue = queue;
}
public interface OnExecuted {
void onExecution(Result result);
}
void execute() {
executeOperation((result) -> {
queue.addResult(result);
queue.next();
}
);
}
abstract public void executeOperation(OnExecuted onExecuted);
}
public class Queue {
public interface OnQueueFinish {
void onQueueFinish(LinkedList<Result> results);
}
final LinkedList<Result> results = new LinkedList<>();
final LinkedList<Operation> operations = new LinkedList<>();
private int currentOperation = -1;
final OnQueueFinish onFinish;
public Queue(OnQueueFinish onFinish) {
this.onFinish = onFinish;
}
public void addOperation(Operation operation) {
operations.addLast(operation);
}
void addResult(Result result) {
results.addLast(result);
if(result.result > NEXT) {
onFinish.onQueueFinish(results);
}
}
public void next() {
currentOperation++;
if(currentOperation >= operations.size()) {
addResult(new Result(NO_NEXT, null, null));
}
operations.get(currentOperation).execute();
}
}
public class GetOperation extends Operation {
final URI uri;
final int onSuccessCode;
final int onErrorCode;
public GetOperation(Queue queue, URI uri, int onSuccessCode, int onErrorCode) {
super(queue);
this.uri = uri;
this.onErrorCode = onErrorCode;
this.onSuccessCode = onSuccessCode;
}
@Override
public void executeOperation(OnExecuted onExecuted) {
// На замыканиях
SomeApi.get(uri)
.onSuccess((data, code) -> onExecuted.onExecution(new Result(onSuccessCode, data, null)))
.onError((code, tr) -> onExecuted.onExecution(new Result(onErrorCode, data, null))).run();
// По обычному
try {
Response r = SomeApi.get(uri);
onExecuted.onExecution(new Result(onSuccessCode, r.getData(), null));
} catch (Throwable tr) {
onExecuted.onExecution(new Result(onErrorCode, null, null));
}
}
}
public class Something {
public Something() {}
void wreeee() {
Queue queue = new Queue(this::onQueueFinished);
// очередь будет продолжена даже при ошибке
queue.addOperation(new GetOperation(queue, new URI("http://somehub.com"), NEXT, NEXT));
// в случае ошибки очередь остановится
queue.addOperation(new GetOperation(queue, new URI("http://oldwomenneedyou.com"), NEXT, ERROR));
// останавливаем очередь на последнем элементе вручную
queue.addOperation(new GetOperation(queue, new URI("http://brotherlove.com"), FINISH, ERROR));
// Тут запускаем очередь
queue.next();
}
void onQueueFinished(LinkedList<Result> results) {
// Тут список результатов обрабатываете, ошибки и т.п.
}
}
С синхронизаций, аннотациями контрактов, исключениями, таймаутами и прочей шелухой сами разберетесь.