如何取消多线程中的DefaulHttpClient执行过程
我正在开发一个非常依赖互联网的Android应用程序,我经常使用这个RestClient类检索数据,它包装了一些有关使用 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请求呢?在这种情况下,应用程序仍然处于一个活动中,例如我创建一个对话框,用户从该对话框中发出请求,然后按下后退按钮,对话框消失,我需要当时取消该请求。
I am developing an android application that rely very much on internet, I retrieve data frequently using this RestClient Class, that wrap some detail on using DefaultHttpClient to do network request.
And I always use different thread to do the HTTP request, I create a class like this:
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...
So whenever I need to do a HTTP request, I only need to create AsyncWorker
object, and provide the RequestListener
callback interface.
But the problem is, how can I cancel the HTTP Request when the user press the back/cancel button? and in this case the application still is in one activity, for example I create a dialog, and the user do a request from that dialog, and then back button pressed, the dialog dismissed, and I need to cancel the request on that time.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我遇到了同样的问题并且能够找到解决方案。以下是我所做的:
我使用 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。实例)
建议:实际取消 http 请求的一个位置可以在进度对话框的 OnCancel 侦听器中,而不是在AyncTask 的 onCancelled() 回调方法。
I had the same issue and was able to find a fix. Here is what I did:
I used CloseableHttpClient along with other related classes, instead of the DefaultHttpClient that by default comes with Android.
These classes are from https://hc.apache.org/downloads.cgi. OR for direcet access: http://apache.mirrors.hoobly.com//httpcomponents/httpclient/binary/httpcomponents-client-4.3.2-bin.tar.gz
With this, calling the abort() method on the Request object will actually halt the connection. However, using this library is not the solution; reason being that Android already has the outdated HTTPCLIENT library inbuilt, and most classes in the library pointed to by the above link would appear to be missing at runtime.
The problem is that both the packages in the above library and the inbuilt org.apache httpclient package have same namespace, and would result in the use of only the inbuilt org.apache classes provided by Android at compilation.
An example of this issue is found here: java.lang.NoSuchFieldError: org.apache.http.message.BasicLineFormatter.INSTANCE.
Thanks to the guys who provided http://code.google.com/p/httpclientandroidlib/ as an option (found in the answer section of java.lang.NoSuchFieldError: org.apache.http.message.BasicLineFormatter.INSTANCE)
Recommendation: one place to actually cancel an http request could be within OnCancel Listener of a progress dialog, instead of the AyncTask's onCancelled() callback method.
您使用的
RestClient
对象不会公开DefaultHttpClient
的任何interrupt()
方法(这是完成大部分工作的支持对象)。不是问题 - DefaultHttpClient 似乎没有任何中断或中止功能可以首先公开。因此,您在
client.Execute()
上留下了阻塞操作。找到解决方案的一半方法 - 即将阻塞操作放入线程中。你的失败之处在于你的架构——你使用的线程/监听器设置并没有给你太多的回旋余地。
尝试将匿名
Thread
切换为AsyncTask
。这不会解决client.Execute()
阻塞的问题,但允许您丢弃侦听器(用onProgressUpdate()
或 <代码>onPostExecute())。这将允许您调用
task.cancel()
,向任务发出不再需要的信号。这将允许您重新分配一个新的 AsyncTask,孤立已取消的任务,然后孤立的线程将尽快完成并安静地死亡,而应用程序的其余部分则继续执行其需要的操作。((在不相关的注释中,“Execute()”是一种方法,不应大写))
The
RestClient
object your using doesn't expose anyinterrupt()
method ofDefaultHttpClient
(which is the backing object doing most of the work). Not a problem - the DefaultHttpClient doesn't seem to have any interrupt or abort functionality to expose in the first place.So, your left with a blocking operation on
client.Execute()
.Your half way to having a solution - which is to put the blocking operation into a Thread. Where your falling down is your architecture - your using a Thread/Listener setup which doesn't give you alot of wiggle room.
Try switching your anonymous
Thread
to anAsyncTask
. This won't solve the problem of you'reclient.Execute()
from blocking but will allow you to throw away the listener (replacing it withonProgressUpdate()
oronPostExecute()
).What this will do is allow you call
task.cancel()
, signalling to the Task it is no longer needed. This will allow you to reassign a new AsyncTask, orphaning the cancelled task, the orphaned thread will then finish quickly as its able and die quietly while the rest of your application gets on with what it needs to.((On an unrelated note, "Execute()" is a method and shouldn't be capitalised))
我建议您看一下
ClientConnectionManager
界面。这允许您执行释放连接、关闭连接等操作。不过,您可能需要增强RestClient
的实现 - 因为您的RestClient
不会公开底层DefaultHttpClient
对象(您可以使用getClientConnectionManager()
方法从该对象获取ClientConnectionManager
)。I suggest you take a look at the
ClientConnectionManager
interface. This allows you to do stuff like releasing a connection, shutting down a connection etc. You may need to enhance the implementation ofRestClient
though - since yourRestClient
does not expose the underlyingDefaultHttpClient
object (from which you can get to theClientConnectionManager
using thegetClientConnectionManager()
method).使用线程原语。有一个标志
running
并最初将其设置为true
。在while(running)
循环中执行 REST 请求。在
onPause()
中,将运行标志设置为false
。Use the threading primitives. Have a flag
running
and set it totrue
initially. Do your REST requests in awhile(running)
loop.In your
onPause()
, set the running flag tofalse
.