3

我有一个应用程序可以进行大量 RESTful 服务调用。我在扩展 Asynctask 的类中执行调用。如果我必须取消异步任务,我也想取消服务调用。不幸的是,取消异步操作仍然允许 doInBackground 完成,并且一旦请求正在等待响应(这可能需要一点时间),我就无法调用 isCancelled() 。现在,在我的 doInBackground 方法中,我正在注册以在发出取消请求时从 UI 线程收到通知,因此我可以中止 HttpResponse 对象。这是一段示例代码。

到目前为止它一直有效,但我真的可以指望它,还是我只是走运?你能指望一个线程调用另一个线程中的方法吗?

public class AsyncTestActivity extends Activity {

private ArrayList<IStopRequestMonitor> monitors;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main2);
}

public void stopActivity() {
    if (monitors == null || monitors.size() < 1) return;

    for (int i = 0; i < monitors.size(); i++) {
        monitors.get(i).stopRequest();
    }
}

public void addListener(IStopRequestMonitor listener) {
    if (monitors == null) monitors = new ArrayList<IStopRequestMonitor>();
    monitors.add(listener);
}

public void readWebpage(View view) {
    DownloadWebPageTask task = new DownloadWebPageTask();
    task.execute(new String[] { "http://www.mywebsite.com/feeds/rsstest.xml" });
}

private class DownloadWebPageTask extends AsyncTask<String, Void, String> {
    @Override
    protected String doInBackground(String... urls) {
        DefaultHttpClient client = new DefaultHttpClient();
        final HttpGet httpGet = new HttpGet(urls[0]);

        addListener(new IStopRequestMonitor() {

            public void stopRequest() {
                if (httpGet == null) return;
                httpGet.abort();
                cancel(true);
            }
        });

        try {
            HttpResponse execute = client.execute(httpGet);
            InputStream content = execute.getEntity().getContent();

            // handle inputstream
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    @Override
    protected void onPostExecute(String result) {
        Log.d("Result:", result);
    }
}

interface IStopRequestMonitor {
    public void stopRequest();
}
}
4

2 回答 2

2

这里还有一场比赛。如果 stopActivity() 在后台线程调用 addListener() 之前运行,监听器将在稍后添加,并且永远不会被调用以中止 HttpGet。

如果您要从 UI 线程(或您创建 AsyncTask 的任何线程)调用 cancel(),您可以:

  1. 在 AsyncTask 中创建一个“私有 HttpGet httpGet”字段。
  2. 覆盖 onPreExecute() 并在那里初始化 httpGet。
  3. 覆盖 onCancel() 并说 'if (httpGet != null) { httpGet.abort() }'
  4. 在 doInBackground() 中,如果 isCancelled() 则立即返回,否则运行。

因为这会在 UI 线程上初始化 httpGet,所以 cancel() 调用将在 execute() 之前运行(因此 doInBackground 将看到 isCancelled() 返回 true),或者它将在 httpGet 存在之后运行,因此 HttpGet 将被中止。

除非您将其用于其他用途,否则您不需要侦听器。

于 2013-04-19T07:09:24.103 回答
1

您可以定义 asynctask 类的全局对象,并在按钮单击或需要时使用 obj.cancle() 方法调用。

于 2013-04-19T04:41:09.937 回答