【问题标题】:How to cancel DefaulHttpClient execution process in multithread如何在多线程中取消 DefaultHttpClient 执行过程
【发布时间】:2011-08-10 08:15:11
【问题描述】:

我正在开发一个非常依赖互联网的 android 应用程序,我经常使用这个 RestClient Class 检索数据,它包含了一些关于使用 DefaultHttpClient 进行网络请求的细节。

而且我总是使用不同的线程来执行 HTTP 请求,我创建了一个这样的类:

public class AsyncWorker {

    final String SERVER_URL = "http://api.blabla.com";
    RestClient client = new RestClient();

    public void requestHttp(final String url, final ArrayList<NameValuePair> params, final RequestListener listener) {
        new Thread(new Runnable() {

            public void run() {
                try {
                    client.setUrl(url);
                    client.setParams(params);
                    client.Execute(RestClient.RequestMethod.POST);
                    String response = client.getResponse();
                    listener.onComplete(response);
                } catch (Exception ex) {
                    Log.d("LOGIN", ex.getMessage());
                }
            }
        }).start();
    }
    etc...

所以每当我需要做一个HTTP请求时,我只需要创建AsyncWorker对象,并提供RequestListener回调接口。

但问题是,当用户按下返回/取消按钮时,如何取消 HTTP 请求?在这种情况下,应用程序仍处于一个活动中,例如我创建了一个对话框,用户从该对话框发出请求,然后按下后退按钮,对话框关闭,我需要在那个时候取消请求。

【问题讨论】:

标签: android multithreading httpclient


【解决方案1】:

我遇到了同样的问题,并且能够找到解决方法。这是我所做的:

我使用 CloseableHttpClient 和其他相关类,而不是 Android 默认自带的 DefaultHttpClient

这些课程来自https://hc.apache.org/downloads.cgi。或直接访问:http://apache.mirrors.hoobly.com//httpcomponents/httpclient/binary/httpcomponents-client-4.3.2-bin.tar.gz

这样,在 Request 对象上调用 abort() 方法实际上会停止连接。但是,使用这个库不是解决方案;原因是 Android 已经内置了过时的 HTTPCLIENT 库,并且上面链接指向的库中的大多数类在运行时似乎都丢失了。

问题是上述库中的包和内置的org.apache httpclient包都有相同的命名空间,导致编译时只使用Android提供的内置org.apache类。

在此处可以找到此问题的一个示例:java.lang.NoSuchFieldError: org.apache.http.message.BasicLineFormatter.INSTANCE

感谢提供http://code.google.com/p/httpclientandroidlib/ 作为选项的人(在java.lang.NoSuchFieldError: org.apache.http.message.BasicLineFormatter.INSTANCE 的答案部分找到)

建议:实际取消 http 请求的一个地方可以是进度对话框的 OnCancel 侦听器,而不是 AyncTask 的 onCancelled() 回调方法。

【讨论】:

  • 这很奇怪,对我来说,使用 DefaultHttpClient 中止请求时应该抛出的 IOException 没有发生。 (我在我的任务 doInBackground() 中中止了 if(isCancelled()))。如果我在进度对话框的 onCancel() 中中止,它确实会抛出,但它不会在任务本身的 onCancelled() 中抛出——这一切都非常令人困惑!
【解决方案2】:

您使用的RestClient 对象不会公开DefaultHttpClient 的任何interrupt() 方法(这是完成大部分工作的支持对象)。没问题 - DefaultHttpClient 似乎一开始就没有任何中断或中止功能要公开。

所以,你的左边对client.Execute() 进行了阻塞操作。

您获得解决方案的中途 - 将阻塞操作放入线程中。你失败的地方是你的架构——你使用的线程/侦听器设置不会给你很大的回旋余地。

尝试将您的匿名 Thread 切换为 AsyncTask。这不会解决您的client.Execute() 阻塞问题,但可以让您丢弃侦听器(将其替换为onProgressUpdate()onPostExecute())。

这将允许您调用task.cancel(),向不再需要它的任务发出信号。这将允许您重新分配一个新的 AsyncTask,孤立已取消的任务,然后孤立的线程将尽可能快地完成并安静地死亡,而您的应用程序的其余部分继续执行它需要的任务。

((在不相关的注释中,“Execute()”是一种方法,不应大写))

【讨论】:

  • 谢谢,已经解决了,我最终利用AsyncTaskcancel()方法,在onCanceled()里面做http uri requestabort()方法。
  • 谢谢阿尤布林。您最后的评论最终提供了我需要的解决方案。当我尝试调用 abort() 以响应 ui 线程上的取消按钮时,我得到了一个 android.os.NetworkOnMainThreadException。
【解决方案3】:

我建议你看看ClientConnectionManager 接口。这允许您执行诸如释放连接、关闭连接等操作。您可能需要增强 RestClient 的实现 - 因为您的 RestClient 不会暴露底层的 DefaultHttpClient 对象(您可以从中获取到ClientConnectionManager 使用getClientConnectionManager() 方法)。

【讨论】:

  • 好的,谢谢,我认为它可以停止与线程有关,但现在我认为我必须增强 RestClient 类。谢谢。
【解决方案4】:

使用线程原语。有一个标志running 并最初将其设置为true。在while(running) 循环中执行您的 REST 请求。

在您的onPause() 中,将运行标志设置为false

【讨论】:

  • 您也可以考虑将设置标志为false 的代码放在synchronized 块中。
  • 好的,我会尝试,但情况是它仍然在一个活动中,例如我显示一个对话框,用户从那里发出请求,然后按返回按钮,对话框关闭,并且我需要取消那个时候的请求,这种情况下我不能使用onPause(),抱歉之前不清楚。
  • 好吧,onPause() 只是一个例子。我的观点是 - 每当您想取消线程正在执行的工作时,请将“正在运行”标志(这是该线程的成员变量)设置为 false。您可以扩展此习惯用法以执行暂停和恢复线程之类的操作。在您的情况下,当使用关闭对话框时,将“运行”标志设置为false
  • 哦,我知道了,让我先尝试一下,如果您有空闲时间,这里的一些示例代码或链接将不胜感激。谢谢:D
  • 我应该把while(flag)放在哪里?我使用while(flag)将所有代码包装在run()中,如果标志设置为true,它将保持线程无限运行,如果设置为false,它不会取消任何东西,它仍然会执行该过程一次。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-10
相关资源
最近更新 更多