简体   繁体   English

如何取消Android / Java线程中的长时间操作?

[英]How do I cancel a long operation in a thread in Android / Java?

While the following code is executing, I want the ability to stop it from running, even if it's halfway done. 在执行以下代码时,我希望能够停止运行,即使它已完成一半。 For example, if I have a boolean x = true; 例如,如果我有一个boolean x = true; then I want to send some king of stop(ReadJSONFeedMainTask); 然后我想发送一些stop(ReadJSONFeedMainTask);stop(ReadJSONFeedMainTask); command to this thread/class. 该线程/类的命令。 I want to cancel everything, even what may be occurring in onPostExecute() . 我想取消所有内容,甚至取消onPostExecute()可能发生的onPostExecute() How can I do this? 我怎样才能做到这一点?

Here is my code: 这是我的代码:

private void doStuff() {
    new ReadJSONFeedMainTask().execute(urlString);
}

private class ReadJSONFeedMainTask extends AsyncTask<String, Void, String> {
    protected String doInBackground(String... urls) {
        return Helper.readJSONFeed(urls[0]);
    }

    protected void onPostExecute(String result) {

        try {      
            dictItems = new ArrayList<HashMap<?, ?>>();
            JSONArray jsonArray = new JSONArray(result);
            Log.i("JSON", "Number of items in feed: " + jsonArray.length());

            for (int i = 0; i < jsonArray.length(); i++) {
                JSONObject jsonObject = jsonArray.getJSONObject(i);

                HashMap<String, String> map = new HashMap<String, String>();

                Iterator<?> it = jsonObject.keys();
                while (it.hasNext())
                {
                      // do a bunch of time consuming stuff
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }  
    }
}

To cancel the task, do asyncTaskVariable.cancel(). 要取消任务,请执行asyncTaskVariable.cancel()。 If it's already in onPostExecute it's going to have to finish it though- you're on the UI thread and can't kill it. 如果它已经在onPostExecute中,则必须完成它-您位于UI线程上并且无法终止它。 Best you can do there is set a variable that tells it to terminate (from another thread of course), and have it check that variable periodically, returning if its set. 最好的办法是设置一个变量,告诉它终止(当然是从另一个线程终止),并让它定期检查该变量,并返回是否设置了该变量。

Just skip out when x is true x为真时就跳过

 while (it.hasNext() && x == false) // where x is your skip boolean
 {
      // do a bunch of time consuming stuff
 }

and do similar in any other methods you want to terminate. 并在您要终止的任何其他方法中执行类似的操作。

Its much safer than terminating it mid flow, as this can cause unusual behaviour. 它比终止中间流安全得多,因为这可能会导致异常行为。

You should call 你应该打电话

asyncTaskVariable.cancel( true );

this will force the asynctask to stop. 这将强制asynctask停止。

BUT, you should know that is won't stop immediatly. 但是,您应该知道那不会立即停止。

If the thread is waiting for IO input, it will be in the "blocked io state". 如果线程正在等待IO输入,则它将处于“阻塞io状态”。 Then it won't be stopped. 这样它就不会停止。 If you don't have control over what happens in this Helper method, you can't change anything. 如果您无法控制此Helper方法中发生的事情,则无法进行任何更改。 But if you own it, then you can loop through the input stream and read it by a number of bytes each time (using a buffer). 但是,如果您拥有它,则可以遍历输入流并每次(使用缓冲区)读取多个字节。 This will give you opportunities to stop your threead. 这将使您有机会停止三合会。 For that do something like 为此做类似

int readBytes = 0;
while( readBytes != -1 && !Thread.interrupted ) {
   readBytes = bufferedReader.read( buffer );
   if( readBytes >0 ) { 
      stringBuilder.append( buffer, 0, readBytes ); 
   }
}

using the interrupted flag, you will be able to stop your thread when your asynctask is cancelled. 使用interrupted标志,您可以在取消异步任务时停止线程。

You should consider not using an AsyncTask for your network operations. 您应该考虑不对网络操作使用AsyncTask They have been designed for short living tasks. 它们被设计用于短期工作。

AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTask被设计为围绕Thread和Handler的帮助器类,并且不构成通用的线程框架。 AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent pacakge such as Executor, ThreadPoolExecutor and FutureTask. 理想情况下,应将AsyncTasks用于较短的操作(最多几秒钟)。如果需要使线程长时间运行,则强烈建议您使用java.util.concurrent pacakge提供的各种API,例如执行程序,ThreadPoolExecutor和FutureTask。

An alternative is to use an Android Service, like with the RoboSpice library. 一种替代方法是使用Android服务,例如RoboSpice库。

You need to keep a reference to your class in order to do that. 为此,您需要保留对类的引用。 For example... 例如...

private ReadJSONFeedMainTask foo;

private void doStuff() {
    foo = new ReadJSONFeedMainTask();
    foo.execute(urlString);
}

Then later on when you have an interrupt event you can just call 然后,当您遇到中断事件时,您可以调用

foo.cancel(true);

The true parameter indicates an immediate interrupt. true参数表示立即中断。

EDIT I didnt notice your placement of the longrunning task in the postexecute. 编辑我没有注意到您在后执行中放置了长期运行的任务。 As gabe mentioned correctly, even cancel() will not help you there. 正如gabe正确提到的那样,即使cancel()也无法帮助您。 You will need to refactor your code to put the longrunning task in the doInBackground method so that it is immediately cancelable, in addition to holding a reference to it as above. 您将需要重构代码,以便将doInBackground运行的任务放入doInBackground方法中,以便除了保留上述引用之外,还可以立即取消该任务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM