改造中依次有多个类似的请求

时间:2017-06-28 10:40:07

标签: java android kotlin retrofit retrofit2

有没有办法在Retrofit中按顺序执行多个请求?

这些请求使用相同的Java接口,并且仅由ArrayList中包含的参数区别。

对于请求A1,A2,A3,A4,A5 ...... An

  1. 点击A1,
  2. 2. A1的onResponse()被称为

    1. 点击A2,
    2. 2。onResponse()的A2被称为

      1. 点击A3
      2. 。 An的onResponse()被称为。

3 个答案:

答案 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个请求将被发送到服务器,但它需要一个请求的时间来获取它们的所有响应并进行处理。

我根本没有测试过这个代码,它可能有一些错误和错误,我只是为了这个问题写了一个想法。