【问题标题】:Can we use Retrofit inside a loop in android studio?我们可以在 android studio 的循环中使用 Retrofit 吗?
【发布时间】:2020-10-15 21:44:16
【问题描述】:

我知道这种奇怪的问题,但我试图在 for 循环中使用我的 Retrofit 调用。我正在做的是在调用中一个一个地发送我的 String[] 元素,比如insertdata(seperated2[0], seperated2[1], email, tag);

但是当他们跳过call.enqueue(......onResponse(...) onfailure(.....))的匿名调用时,循环的行为很奇怪

不是用循环控制调用它,而是先完成循环,然后调用 call.enqueue 并且总是循环中的最后一个元素。这就是循环的样子......

 separated = currentString.split("\n");
for (int i=1; i<separated.length; i++) {
        seperated2 = separated[i].split(":");


        for (String aSeperated2 : seperated2) {
            Call<ServerResponse2> call = requestInterface.insertQrdata(seperated2[0], seperated2[1], email, tag);
            call.enqueue(new Callback<ServerResponse2>() {
                @Override
                public void onResponse(Call<ServerResponse2> call, Response<ServerResponse2> response) {
                    ServerResponse2 serverResponse2 = response.body();
                    Toast.makeText(getActivity(), serverResponse2 != null ? serverResponse2.getMessage() : null, Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onFailure(Call<ServerResponse2> call, Throwable t) {
                    Toast.makeText(getActivity(), t.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
                }
            });

        }

    }

这里是 seperated[] 和 seperated2[] 的一个例子

0 1
2 3
4 5
6 7
7 8
9 10

seperated[] 按行拆分,seperated2 按列拆分。

问题 当我检查 Response 方法中每次迭代的 seperated2[0] 和 seperated2[1] 值时,它应该是

sep2[0]= 0 sep2[1] = 1 
        2           3
and so on... for each iteration 

但在每次迭代中,onResponse 中的值始终是最后一个,即

sep2[0] = 9  sep2[1] = 10
untill the length (say 6) same value at each iteration.

我不知道我是否做错了什么,但是当我在 onResponse() 之外使用它们时,值显示正确。

我知道使用 Retrofit like 不是一个好习惯,但我很好奇它在这种情况下会如何反应。任何人都可以提供帮助或提供任何建议吗?

提前致谢!!

【问题讨论】:

  • 是的!如此频繁地进行 API 调用是不好的做法。您可以先准备您的字符串/字符列表,然后进行一次 API 调用,只需一次调用即可接收整个列表。
  • 是的,我知道并且已经这样做了,但我试图检查它会如何反应,所以你有解决这个问题的方法或任何想法吗? @JeelVankhede
  • 主循环 (在主循环中初始化它)中本地获取seperated2变量,现在它被声明在主循环之外。
  • 你的意思是在嵌套的循环内??
  • 我的意思是代替seperated2 = separated[i].split(":");,试试String[] seperated2 = separated[i].split(":");

标签: android android-studio for-loop retrofit retrofit2


【解决方案1】:

这是一个使用改造库进行循环的示例。如果我们使用 for 循环,则所有迭代都不会立即调用 call.enqueue。所以请使用此模型。

private void UploadImagesTask(final String image, final int position) {
    ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
    File file = new File(image);
    RequestBody reqFile = RequestBody.create(MediaType.parse("image/*"), file);
    MultipartBody.Part photoArray = MultipartBody.Part.createFormData("photo", file.getName(), reqFile);
    HashMap<String, RequestBody> params = new HashMap<>();
    params.put("token", Utils.createPartFromString(pref.getToken()));
    params.put("app_id", Utils.createPartFromString(pref.getAppId()));
    Call<ImageUploadResponse> imageUploadResponseCall = apiService.uploadImage(photoArray, params);
    imageUploadResponseCall.enqueue(new Callback<ImageUploadResponse>() {
        @Override
        public void onResponse(@NonNull Call<ImageUploadResponse> call, @NonNull Response<ImageUploadResponse> response) {

            if (response.isSuccessful()) {
                urlList.add(Objects.requireNonNull(response.body()).getUrl());
                completeData.remove(position);
                completeData.add(position, getString(R.string.uploaded));
                uploadAdapter.notifyDataSetChanged();
                pref.setTempData(Constants.IMAGE_UPLOADED, gson.toJson(urlList));
                if (position != uriData.size() - 1) {
                    int posi = position + 1;
                    CompressImages(posi);
                } else {
                    uploadDone.setActivated(true);
                    uploadDone.setEnabled(true);
                }
            } else {
                Utils.showSnackView(getString(R.string.error_occurred), snackView);
                uploadDone.setActivated(true);
                uploadDone.setEnabled(true);
            }
        }

        @Override
        public void onFailure(@NonNull Call<ImageUploadResponse> call, @NonNull Throwable t) {
            Utils.showSnackView(getString(R.string.error_occurred), snackView);
            uploadDone.setActivated(true);
            uploadDone.setEnabled(true);
        }
    });
}

【讨论】:

    【解决方案2】:

    您也可以使用递归,而不是使用 for 循环。 API 将被一次又一次地调用,但只有在获得前一个索引的响应之后。 在 onResponse() 方法中,您可以通过增加索引值来调用该方法。 因为在for循环中,迭代不会等待你的API响应执行完成,会跳转到下一次迭代。

    如果你还想使用循环,那就去 for while 循环

    递归示例:

        int i=1;
        separated = currentString.split("\n");
    
        void callMethod(){
    seperated2 = separated[i].split(":");
     Call<ServerResponse2> call = requestInterface.insertQrdata(seperated2[0], seperated2[1], email, tag);
                call.enqueue(new Callback<ServerResponse2>() {
        @Override
        public void onResponse(Call<ServerResponse2> call, Response<ServerResponse2> response) {
                ServerResponse2 serverResponse2 = response.body();
                Toast.makeText(getActivity(), serverResponse2 != null ? serverResponse2.getMessage() : null, Toast.LENGTH_SHORT).show();
                i++;
                callMethod();
                }
    
        @Override
        public void onFailure(Call<ServerResponse2> call, Throwable t) {
                Toast.makeText(getActivity(), t.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
                }
                });
    

    【讨论】:

      【解决方案3】:

      根据我的建议,不要对此类操作使用循环。这是个坏主意,如果你能看到性能方面的话。

      您可以通过以下方式执行此操作:

      Retrofit 只是调用服务器 URL 并将您的数据传递给服务器。 因此,无论执行服务器端的进程,您都可以更改为只执行一次,而不是每次都执行。

      您可以一次将整个循环数据以 json 格式传递给服务器,并在服务器端执行所有循环过程。这对你来说是最好的。

      希望你能澄清我的观点。

      如果您有任何问题,请告诉我。

      【讨论】:

      • 出于某种原因,他以块的形式发送数据 - 您是否注意到他已经拥有全部数据,但他将其分开(甚至两次!)?
      • 是的,这就是我想说的。不要分开,按原样发送。
      • 好吧,我换个说法:既然他能一次性发送原始的海量数据,他为什么要如此努力并分离他的数据?他必须有充分的理由......
      • 那么一旦他得到previous call的成功响应,他就必须发送API的next call,但不必那样调用。
      • 他基本上必须使用synchronous改造模式——仅此而已
      【解决方案4】:

      嘿,如果你还没有找到答案,我有一个建议给你。在对该数据应用循环之后将整个响应划分为多个部分,并使用 Asynctask 将数据发送到服务器并创建一个接口,以便您可以在响应返回时执行任何操作。

                  public interface GetResponse{
                  
                  public void onSuccess(ResponseModel model);
                  
                  publich void onFail();
                  
                  }
              
              In your async task
              
              public class AsyncTaskForApiSync extends AsyncTask<Void, Void, Void> {
      
              GetResponse mcallback;
              
      public AsyncTaskForApiSync(GetResponse mcallBack){
          
                  this.mcallback=mcallBack;
              
                }
              
               @Override
                  protected Void doInBackground(Void... voids) {
              
              //retrofit api call in on success
          
              mcallback.onSuccess(response);
          
              }
          
              }
      

      对不起我的英语。另外,如果您发现任何问题,请告诉我。谢谢。

      【讨论】:

        猜你喜欢
        • 2020-09-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-07
        • 2018-03-10
        • 2017-12-31
        相关资源
        最近更新 更多