Java 一段时间后取消异步任务
这可能是一个重复的问题,但我没有找到我要找的。 我正在UI活动Java 一段时间后取消异步任务,java,android,android-asynctask,Java,Android,Android Asynctask,这可能是一个重复的问题,但我没有找到我要找的。 我正在UI活动new LoadData().execute()中调用一个异步任务
new LoadData().execute()中调用一个异步任务在doInBackground中,我调用了一个需要时间的方法。如果数据在一段时间后没有返回,我想中断这个线程。
下面是我如何尝试这样做的代码
class LoadData extends AsyncTask<String, String, String>
{
@Override
protected void onPreExecute() {
super.onPreExecute();
startTime = System.currentTimeMillis();
}
protected String doInBackground(String... args)
{
DataCollector dc = new DataCollector();
data = dc.collectData(query);
//Here I check if the time is greater than 30 seconds then cancel
if(((System.currentTimeMillis()-startTime)/1000)>30)
{
cancel(true);
}
return null;
}
}
class LoadData扩展了异步任务
{
@凌驾
受保护的void onPreExecute(){
super.onPreExecute();
startTime=System.currentTimeMillis();
}
受保护的字符串doInBackground(字符串…args)
{
DataCollector dc=新的DataCollector();
数据=dc.collectData(查询);
//这里我检查时间是否大于30秒,然后取消
如果(((System.currentTimeMillis()-startTime)/1000)大于30)
{
取消(真);
}
返回null;
}
}
但这并不能在30秒后停止任务,事实上这需要更多的时间。
我尝试了get(长超时,时间单位)代码>,但这也不起作用
有人能告诉我怎么做吗?或者我如何在doInBackground中使用isCancelled()
谢谢。您必须在不同的线程上执行时间检查
您当前要做的是:执行dc.collectData(查询)
(在后台)并在准备好后检查是否应该取消。因此,如果查询需要1分钟,您将在1分钟后执行取消检查,这已经太晚了
您可以做的是安排一个TimerTask,它应该在LoadData().execute()之后运行30秒,如果计时器任务已运行,您可以取消异步任务(如果它仍在运行)尝试以下操作:
public class MyTask extends AsyncTask<Void, Void, Void> {
private volatile boolean running = true;
private final ProgressDialog progressDialog;
public MyTask(Context ctx) {
progressDialog = gimmeOne(ctx);
progressDialog.setCancelable(true);
progressDialog.setOnCancelListener(new OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
// actually could set running = false; right here, but I'll
// stick to contract.
cancel(true);
}
});
}
@Override
protected void onPreExecute() {
progressDialog.show();
}
@Override
protected void onCancelled() {
running = false;
}
@Override
protected Void doInBackground(Void... params) {
while (running) {
// does the hard work
}
return null;
}
// ...
}
公共类MyTask扩展了AsyncTask{
private volatile boolean running=true;
私人最终进度对话;
公共MyTask(上下文ctx){
progressDialog=gimmeOne(ctx);
progressDialog.setCancelable(真);
progressDialog.setOnCancelListener(新的OnCancelListener(){
@凌驾
public void onCancel(对话框接口对话框){
//实际上可以设置running=false;就在这里,但我会
//坚持合同。
取消(真);
}
});
}
@凌驾
受保护的void onPreExecute(){
progressDialog.show();
}
@凌驾
受保护的void onCancelled(){
运行=错误;
}
@凌驾
受保护的Void doInBackground(Void…参数){
(跑步时){
//这项工作很辛苦吗
}
返回null;
}
// ...
}
有关更多详细信息,请参阅此答案。简短的答案是,异步任务一旦启动,您就不能取消它。您可以做的是在doInBackGround()
中插入一个循环,该循环将检查isCancelled()
,如果它在将来某个时候被设置为true,则从函数返回一个值(如果您已经定义了它,它将依次调用onPostExecute()
)
请注意,不能停止异步任务并不意味着操作系统在内存不足时不会取消它。如果您在AsyncTask中执行基本任务(您希望100%执行的任务),您应该记住这一点。如果是这样的话,最好使用一个-a组件,该组件会根据需要由操作系统自动终止并重新启动。您需要一个线程,该线程会在一段时间后取消任务。该线程可能如下所示:
public class TaskCanceler implements Runnable{
private AsyncTask task;
public TaskCanceler(AsyncTask task) {
this.task = task;
}
@Override
public void run() {
if (task.getStatus() == AsyncTask.Status.RUNNING )
task.cancel(true);
}
}
protected async Task<String> doInBackgroundAsync(String... args)
{
DataCollector dc = new DataCollector();
int timeout = 1000;
var task = dc.collectDataAsync(query);
if (await Task.WhenAny(task, Task.Delay(timeout)) == task) {
// task completed within timeout
data = task.Result;
} else {
// timeout logic
}
}
当调用AsyncTask时,需要在一定时间后运行cancle任务(=超时,在本例中为20秒)
这是一个好主意,如果你清理这个取消或结束与
if(taskCanceler != null && handler != null) {
handler.removeCallbacks(taskCanceler);
}
当然,您可以将其包装到AsyncTask的自定义实现中。我已经用过很多次了,它就像一个符咒。需要注意的一点是,在极少数情况下,处理程序不会启动,我怀疑如果在错误的上下文中创建它,它在某些情况下将无法生存,因此我强制处理程序成为UI线程,并使用handler=new handler(Looper.getMainLooper())代码>我将把这转化为一个异步/等待问题,使所有昂贵的方法都成为异步方法
首先,将DataCollector的collectData(查询)修改为collectDataAsync(查询)。(如果您不能修改DataCollector,那么可以使用lambda函数或类似的方法来包装它)
其次,将doInBackground更改为异步任务,如下所示:
public class TaskCanceler implements Runnable{
private AsyncTask task;
public TaskCanceler(AsyncTask task) {
this.task = task;
}
@Override
public void run() {
if (task.getStatus() == AsyncTask.Status.RUNNING )
task.cancel(true);
}
}
protected async Task<String> doInBackgroundAsync(String... args)
{
DataCollector dc = new DataCollector();
int timeout = 1000;
var task = dc.collectDataAsync(query);
if (await Task.WhenAny(task, Task.Delay(timeout)) == task) {
// task completed within timeout
data = task.Result;
} else {
// timeout logic
}
}
受保护的异步任务doInBackgroundAsync(字符串…args)
{
DataCollector dc=新的DataCollector();
int超时=1000;
var task=dc.collectDataAsync(查询);
if(wait Task.wheny(Task,Task.Delay(timeout))==Task){
//任务在超时时间内完成
数据=任务。结果;
}否则{
//超时逻辑
}
}
基本上,doInBackgroundAsync中有两个任务:collectDataAsync和一个延迟任务。
您的代码等待更快的代码。然后你知道是哪一个,你可以做出相应的反应
如果还需要取消collectDataAsync任务,则需要使用cancellationToken。
我用这个来解决你的问题
注意,现在doInBackgroundAsync是一个异步的,所以它稍微改变了使用它的方式
希望有帮助。这是正确的,但它允许用户始终取消作业,并且在30秒后不会自动取消作业。您可以在后台使用计时器,设置一些时间,例如30秒,然后在发布取消()之后…它将随时停止您的异步任务point@Shruti:谢谢您的参考,但我不想允许用户取消操作。而且cancel(true)
似乎对我不起作用。如何使用get(长超时,时间单位)代码>因为这听起来更可行。事实上,有时由于连接问题或传感器脱机,我通过套接字连接从外部传感器收集数据,这个过程可能需要很长时间