【问题标题】:How to stop enqueued call after first execution?第一次执行后如何停止排队的调用?
【发布时间】:2019-04-02 10:14:18
【问题描述】:

我对 Android 开发非常陌生。尝试连接某个站点并从中获取数据。我在主要活动中仅从 onCreate 调用此函数。每次我向左或向右转动虚拟 Android 手机时,我都会在 EditText 中看到新的“run()”字符串,并在 Wireshark 中看到请求。如何正确停止?

在 OnResponse 中尝试了 call.cancel() 和 mClient.dispatcher().cancelAll()

protected void Load(String url) {
    Request request = new Request.Builder()
            .url(url)
            .build();

    mClient.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            e.printStackTrace();
        }

        @Override
        public void onResponse(Call call, final Response response) throws IOException {
            if (response.isSuccessful()) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mEdit.setText(mEdit.getText() + "run()\n");
                    }
                });
            }
        }

    });
}

【问题讨论】:

  • 发生这种情况是因为重新配置。每次打开手机时都会重新创建您的活动,因此您的 onCreate 会一次又一次地被调用,这反过来会调用您的 loadString 方法。
  • 我在 onCreate 和 Load 的开头添加了跟踪。经过一些轮次后,“onCreate”和“Load”只打印一次,“run”很多imgur.com/dN0Inkr

标签: android okhttp3 enqueue


【解决方案1】:

retrofit 支持取消排队,而且效果很好。 而且我认为如果您尝试运行此代码 - 您的客户端排队将被停止

protected void Load(String url) {
    Request request = new Request.Builder()
            .url(url)
            .build();

    Call<Response> mCall = mClient.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
                if (call.isCanceled()) {
                    Log.e(TAG, "request was cancelled");
                }
                else {
                    Log.e(TAG, "other larger issue, i.e. no network connection?");
                }
        }

        @Override
        public void onResponse(Call call, final Response response) throws IOException {
            if (response.isSuccessful()) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mEdit.setText(mEdit.getText() + "run()\n");
                    }
                });
            }
        }

    });

    mCall.cancel();
}

我不知道你的项目结构和你使用什么样的模式(MVP、MVVM 或其他),但简单来说,可以通过返回 Call 来改进这段代码

protected void Load(String url): Call<Response>

然后您可以处理您的请求状态,例如,如果超过 5 秒,您调用 call.cancel() 并且请求正在停止。

【讨论】:

  • 谢谢。但在您的示例中,调用在执行前取消
【解决方案2】:

每次配置更改时都会调用 onCreate(例如,您旋转手机/模拟器)。欲了解更多信息:https://developer.android.com/guide/components/activities/activity-lifecycle

您可以保存您的响应,以防止在每个 onCreate 上都有新请求。像这样的:

MainActivity {
  private Response savedResponse;

  onCreate() {
    if (savedResponse == null) {
      Load(url)
    }
  }
}

并在您的 onResponse 中保存响应:

 @Override
    public void onResponse(Call call, final Response response) throws IOException {
        if (response.isSuccessful()) {
            savedResponse = response;    // <----
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mEdit.setText(mEdit.getText() + "run()\n");
                }
            });
        }
    }

但是,正确的方法是将网络调用/请求与活动生命周期分开,并将数据加载到其他地方(Service、WorkManager...)

【讨论】:

  • 我考虑过 bool 变量来停止 Load 调用,但这也无济于事。我添加了 mEdit.setText(mEdit.getText() + "Load()\n");到 Load 函数的第一行,它只打印一次(以及“onCreate”)
  • 好的,要在 onDestroy 之后保留变量,您必须实现 onSaveInstanceState。查看此部分:developer.android.com/guide/components/activities/…
  • 但我可能会感到困惑,我以为您只想调用一次 Load 函数。因此,从 Load 函数的第一行只看到一条日志消息应该是正确的。
  • 是的。我只需要一个 Load() 调用和一个 run()。现在我得到了一些奇怪的东西imgur.com/dN0Inkr - 经过四轮
  • 嗯,这很奇怪。我想您的代码中的其他任何地方都没有“run()”日志。如果您只有一个加载日志,我看不出有任何理由从您发布的代码中获得多个运行日志。
猜你喜欢
  • 1970-01-01
  • 2016-08-18
  • 2020-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-30
相关资源
最近更新 更多