有没有办法在Retrofit中按顺序执行多个请求?
这些请求使用相同的Java接口,并且仅由ArrayList
中包含的参数区别。
对于请求A1,A2,A3,A4,A5 ...... An
2. A1的onResponse()
被称为
2。onResponse()
的A2被称为
。
An的onResponse()
被称为。
答案 0 :(得分:3)
使用RxJava可以轻松解决问题。
假设您有一个改装Api
类,则会返回Completable
:
interface Api {
@GET(...)
fun getUser(id: String): Completable
}
然后你可以执行此操作:
// Create a stream, that emits each item from the list, in this case "param1" continued with "param2" and then "param3"
Observable.fromIterable(listOf("param1", "param2", "param3"))
// we are converting `Observable` stream into `Completable`
// also we perform request here: first time parameter `it` is equal to "param1", so a request is being made with "param1"
// execution will halt here until responce is received. If response is successful, only then a call with second param ("param2") will be executed
// then the same again with "param3"
.flatMapCompletable { api.getUser(it) }
// we want request to happen on a background thread
.subscribeOn(Schedulers.io())
// we want to be notified about completition on UI thread
.observeOn(AndroidSchedulers.mainThread())
// here we'll get notified, that operation has either successfully performed OR failed for some reason (specified by `Throwable it`)
.subscribe({ println("completed") }, { println(it.message) })
如果您的改装API未返回Completable
,请将api.getUser(it)
更改为api.getUser(it).toCompletable()
。
答案 1 :(得分:0)
您可以在Rx中使用 zip功能轻松完成此操作(例如:在改造2中的每个请求返回Observable<Object>
)。它将按顺序运行请求。您可以尝试下面的代码:
public Observable buildCombineObserverable() {
List<Observable<Object>> observables = new ArrayList<>();
for (int i = 0; i < number_of_your_request; i++) {
observables.add(your_each_request_with_retrofit);
}
return Observable.zip(observables, new FuncN<Object>() {
@Override
public Object call(Object... args) {
return args;
}
});
}
您可以订阅此Observable并从所有请求中获取数据。 Zip函数将按顺序执行请求,但会压缩数据并将数据作为Object...
答案 2 :(得分:0)
好的,我不知道Retrofit,我使用loopj的库,但概念是一样的。他们都有成功的方法和失败的方法。所以这是我的一般建议:
ArrayList<MyRequest> requests = new ArrayList<>();
int numberOfRequests = 10;
JSONObject params = null;
try{
params = new JSONObject("{\"key\":\"value\"}");
}catch(JSONException e){
e.printStackTrace();
}
MyRequest firstRequest = new MyRequest();
requests.add(firstRequest);
for(int i = 0; i < numberOfRequests; i++){
MyRequest myRequest = new MyRequest();
requests.get(requests.size() - 1).addNextRequest(myRequest);
myRequest.addPreviousRequest(requests.get(requests.size() - 1));
//don't invoke sendRequest before addNextRequest
requests.get(requests.size() - 1).sendRequest(params, "example.com", App.context);
requests.add(myRequest);
}
requests.get(requests.size() - 1).sendRequest(params, "example.com", App.context);
和MyRequest类:
import android.content.Context;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import org.json.JSONObject;
import cz.msebera.android.httpclient.Header;
import cz.msebera.android.httpclient.entity.StringEntity;
public class MyRequest{
private Object result, nextRequestsResult;
private MyRequest nextRequest, previousRequest;
public void addNextRequest(MyRequest nextRequest){
this.nextRequest = nextRequest;
}
public void addPreviousRequest(MyRequest previousRequest){
this.previousRequest = previousRequest;
}
public void sendRequest(JSONObject parameters, String url, Context ctx){
AsyncHttpClient mClient = new AsyncHttpClient();
StringEntity entity = new StringEntity(parameters.toString(), "UTF-8");
String contentType = "application/json";
mClient.post(ctx, url, entity, contentType,
new AsyncHttpResponseHandler(){
private void sendResult(Object... results){
MyRequest.this.result = results;
if(previousRequest != null){
if(nextRequest != null){
if( nextRequestsResult != null){
previousRequest.onResult(results, nextRequestsResult);
}else{
//next request's result is not ready yet
//so we don't do anything here. When nextRequestsResult
//gets ready, it will invoke this request's onResult
}
}else {
//nextRequest == null means this the last request
previousRequest.onResult(results);
}
}else{
//previousRequest == null means this is the first request
if(nextRequest != null){
if(nextRequestsResult != null){
previousRequest.onResult(results, nextRequestsResult);
}else{
//next request's result is not ready yet
//so we don't do anything here. When nextRequestsResult
//gets ready, it will invoke this request's onResult
}
}else{
//next request and previous request are null so it means
//this is the only request, so this is the final destination
doFinalJobWithResults(results);
}
}
}
@Override
public void onSuccess(final int statusCode, final Header[] headers,
final byte[] responseBody){
sendResult(responseBody, true, null, false);//whatever
}
@Override
public void onFailure(final int statusCode, final Header[] headers,
final byte[] responseBody,
final Throwable error){
sendResult(responseBody, error);//or just sendResult();
}
});
}
/**
This method should be invoked only by next request
@param nextRequestsResult
results of the next request which this request is expecting.
*/
private void onResult(Object... nextRequestsResult){
this.nextRequestsResult = nextRequestsResult;
//do whatever you want with the result of next requests here
if(previousRequest != null){
if(result != null){
previousRequest.onResult(result, this.nextRequestsResult);
}
}else{
//if it doesn't have previous request then it means this is the first request
//so since this method gets invoked only by next request then it means
//all of the next requests have done their job and this is the final destination
if(nextRequestsResult != null){
if(this.result != null){
doFinalJobWithResults(nextRequestsResult, this.result);
}
}
}
}
private void doFinalJobWithResults(Object... results){
//whatever
}
}
它是一个通用类,您可以同时发送数百个网络请求,但它们的结果将按顺序处理。 这种方式,例如100个请求将被发送到服务器,但它需要一个请求的时间来获取它们的所有响应并进行处理。
我根本没有测试过这个代码,它可能有一些错误和错误,我只是为了这个问题写了一个想法。