用户按下后取消正在进行的连接
Posted
技术标签:
【中文标题】用户按下后取消正在进行的连接【英文标题】:Cancel an ongoing connection when user presses back 【发布时间】:2011-11-15 12:23:03 【问题描述】:我一直在搜索这个,但我没有找到我的具体问题。我知道AskyncTask
可以使用.cancel(true)
取消,但这只有在我有一个可以检查值isCanceled()
的循环时才会发生。
但我的问题是.. 当用户按下返回时,如何取消 AsyncTask
(卡在 httpclient.execute()
中)?如果用户导航离开该 Activity 并转到另一个我不希望 AsyncTask 运行数量不受控制,因为这可能会导致内存问题,用户可以来回导航并创建未确定数量的任务。这就是为什么我要关闭它们。有人知道方法吗?我发布了我用来连接的代码:
public class Test extends Activity
@Override
protected void onStart()
super.onStart();
new ConnectionTask().execute("https://www.mywebserver.com/webservice.php?param1=test");
private class ConnectionTask extends AsyncTask<String, Void, String>
@Override
protected String doInBackground(String... params)
try
HttpClient httpclient = DefaultHttpClient(params,clientConnectionManager);
HttpPost httpPost = new HttpPost(params[0]);
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
if(httpEntity != null)
return EntityUtils.toString(httpEntity);
catch (Exception e)
e.printStackTrace();
return null;
你知道我应该在 onStop() 中添加什么来取消正在进行的 httpClient.execute() 函数吗?有时几乎永远卡住。
非常感谢您的帮助,非常感谢您。
更新
如果我关闭ConnectionManager
,我必须再次为 https 握手,对吗?在我创建httpClient
时查看此代码,我将其用于 https:
HttpClient httpclient = DefaultHttpClient(params,clientConnectionManager);
感谢大家的快速回复以及此处提供的各种解决方案。我将尝试使用超时(不必等待太多)+cancel()
函数来避免处理onPostExecute
。我会告诉结果是否如预期的那样!非常感谢大家!
【问题讨论】:
您是否尝试取消正在进行的线程? 当您尝试取消 AsyncTask 时,它只是将 isCancelled() 设置为 true,我无法销毁 AsyncTask(我知道),.cancel(true) 不起作用。 试试这个 httpclient.getConnectionManager().shutdown(); 我写了http,但实际上是https。这段代码是简化版,因为我想保留connectionmanager和httpParams以避免进一步握手,有没有办法避免关闭connectionManager? 【参考方案1】:你可以覆盖
onPause()
Activity 的方法并在那里编写停止连接代码。如果选项特定于后退按钮,那么您可以覆盖
onBackButtonPressed()
方法停止执行。
【讨论】:
你知道如何停止连接吗?从 2 个不同的线程访问 httpClient 是否安全?我试过了,但没有这种取消或中止连接的方法......你有什么想法吗?【参考方案2】:AsyncTask
类中有一个cancel()
方法。维护一个成员到 asynctask 并在onDestroy().
中取消它,然后将该成员设置为 null。
更新
使用ClientConnectionManager
关闭连接。
http://developer.android.com/reference/org/apache/http/conn/ClientConnectionManager.html
更新 2
检查此链接以设置连接超时。
How to set HttpResponse timeout for Android in Java
【讨论】:
cancel 方法只是将一个变量设置为 true,实际上并没有关闭 AsyncTask,它被认为是要求高的循环,然后在每次迭代中检查值 isCancelled()。事实并非如此,这样的循环不存在,因此我无法检查 isCancelled()cancel()
将尝试取消任务的执行。如果您希望任务在取消时尽快完成,那么您需要检查isCancelled
,如果为真则返回。你误会了。 developer.android.com/reference/android/os/…
但是看这个:“可以通过调用cancel(boolean)随时取消任务。调用此方法将导致后续调用isCancelled()返回true。调用此方法后,onCancelled( Object), 而不是 onPostExecute(Object) 将在 doInBackground(Object[]) 返回后被调用" 我们仍然需要 doInBackground 来返回,这就是问题所在,它永远不会返回,因为它卡在 httpClient.execute() 中,我我错了吗? :S
你在你的上下文中是对的。我更新了我的答案。您可以设置连接超时。【参考方案3】:
在onPause()
或onBackButtonPressed()
中,就您的任务致电cancel()
。在doInBackground()
之后
HttpResponse httpResponse = httpClient.execute(httpPost);
检查isCanceled()
,如果为真则立即返回。
当然,您仍然有运行多个任务的风险,但是由于此操作是 UI 驱动的(即由用户交互启动的任务),因此最多应该有几个同时运行,前提是超时关于 HttpClient 是合理的。
更新
一旦确定需要取消任务,您也可以关闭连接管理器。 see docs
这应该关闭套接字并立即从execute()
返回。连接管理器在您创建 DefaultHttpClient
时设置。
【讨论】:
我该如何设置超时,因为它现在没有发生,我可以等待超过一两分钟并且没有得到响应。 其实你应该只是关闭连接管理器。我添加了更新。 对不起,我只是写了一个更简单的代码来避免问题中的大量代码,我使用 https 并且想维护连接管理器,所以关闭它会让我再次握手。我想我将不得不使用超时。【参考方案4】:我的理解是httpClient.execute()
是阻塞的,所以没有运行代码来检查isCancelled()
的值。而且您不希望关闭连接管理器。
这可能有点老套,但如果您在线程上调用Thread.interrupt()
而httpClient.execute()
被阻塞,会发生什么情况?
快速测试可以验证这一点,只需在ConnectionTask
定义中添加Thread
类型的私有实例变量,将其设置为doBackground()
顶部的Thread.currentThread()
,并添加一个调用@987654329 的公共方法@就可以了。
如果你很幸运,这将导致httpClient.execute()
立即退出,并抛出异常。您可以在方法调用结束和 AsyncTask
自然结束之前抓住它并做任何您需要做的事情。
【讨论】:
好主意!我会尝试一下,然后返回结果! 它没有带来任何结果...我试着按照你说的做,`AsyncTask private Thread thisThread; @Override protected String doInBackground(String... params) thisThread = Thread.currentThread(); [...] public void cancelConnection() thisThread.interrupt(); ` 但是没有这样的中断......从AsyncTask改为Thread + Handler会有帮助吗? 哦,所以你是从另一个线程调用cancelConnection()
而httpClient.execute()
仍然只是坐在那里?我担心,这就是为什么我说'如果你很幸运'......从Android API文档中它并没有说execute()
抛出InterruptedException,所以它没有承诺它会。由于它不尊重这一点,所以我无法阻止它坐在那里直到超时,抱歉。不过值得一试。不,我认为 Handler 不会产生任何影响,execute()
仍然会挂起 Handler 的线程,直到超时。
非常感谢您的帮助。我一直在尝试没有运气。我将不得不为 userSeven7s sais 实现 .execute()
的超时。再次感谢您;)【参考方案5】:
根据HttpClient docs,使用HttpUriRequest#abort()
中止请求
1.4。中止请求
在某些情况下,由于目标服务器上的高负载或客户端发出的并发请求过多,HTTP 请求执行无法在预期的时间范围内完成。在这种情况下,可能需要提前终止请求并解除阻塞在 I/O 操作中阻塞的执行线程。 HttpClient 正在执行的 HTTP 请求可以通过调用 HttpUriRequest#abort() 方法在执行的任何阶段中止。此方法是线程安全的,可以从任何线程调用。当一个 HTTP 请求被中止时,它的执行线程——即使当前在一个 I/O 操作中被阻塞——通过抛出一个 InterruptedIOException 来保证解除阻塞
【讨论】:
正是我想要的。谢谢。【参考方案6】:这个问题有一个快速的解决方案,我曾经在我的案例中解决过。这可能不是正确的方法,因为当您按下后应用程序会立即响应,但在后台网络操作将继续(如果您设置,则直到超时)而不阻塞应用程序:-
在新服务中执行所有网络操作,例如 NSERV。使 NSERV 扩展 Thread 类并在 run 方法中执行所有网络操作。为了使您的代码更清晰,更好地使启动 NSERV 的活动/服务也扩展 Thread 类并从它们的 run 方法启动 NSERV。
然后使用静态字段或单例从 NSERV 访问活动/服务中的变量。
前:
public class NSERV extends Service implements Runnable
public int onStartCommand (Intent intent, int flags, int startId)
Thread t = new Thread (this, "abc");
t.start();
return super.onStartCommand(intent, flags, startId);
public void run()
//NETWORK OPERATION...
onDestroy();
public void onDestroy()
stopSelf();
super.onDestroy();
【讨论】:
以上是关于用户按下后取消正在进行的连接的主要内容,如果未能解决你的问题,请参考以下文章
登录按钮按下后,如何获取Tkinter entry的值并传递给SQL查询?