如何启用我的运行代码?

时间:2011-08-01 16:07:43

标签: java android multithreading runnable

我在后台运行了很长时间的操作,比如上传内容,转换图片,音频,视频等。 如果用户要求完全停止操作,我想停止/取消它们。

怎么做到这一点?这有设计模式吗?

注意:某些正在运行的代码可以取消,有些则不能取消。我如何找到妥协?

编辑:我应该说我希望操作立即停止。

4 个答案:

答案 0 :(得分:3)

总结并扩展Jon所说的内容:

  • 你应该让线程知道它应该退出循环(volatile flag)。
  • 如果你想让它退出阻止状态,你可以interrupt()线程
  • 您应该处理InterruptedException方法中的run
  • 当你被打断时,你应该优雅地退出(即完成你正在做的任何事情并清理干净)。

一些代码:

private volatile bool _running;// volatile guarantees that the flag will not be cached

public void kill(){_running = false;}
public void run()
{
    while(_running)
    {        
        try
        {
            DoWork(); // you may need to synchronize here
        }
        catch(InterruptedException e)
        {
            // Handle e
        }
    }
}

答案 1 :(得分:2)

(我假设您已经在单独的线程中执行后台工作。)

基本上,您保留一个共享的boolean标志,UI线程可以设置该标志,后台线程会定期读取。当标志显示“停止”时,您停止:)

请注意,该标志应该是易失性的,或者您应该使用锁定以确保后台线程肯定“看到”从UI线程写入的更改。

它相对粗糙,感觉有点“手动”,但这意味着你不会因为操作中途中止而不会有不稳定的风险,这与Thread.stop()等方法不同。

答案 2 :(得分:0)

我的2美分。可取消的任务。需要实施cancelImpl()runImpl()

import java.util.concurrent.CancellationException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

public abstract class CancelableTask extends Observable<CancelableTask>
        implements Runnable {
    private volatile boolean isStarted = false;
    private volatile boolean isCanceled = false;
    private volatile boolean isSuccess = false;
    private volatile Exception e;
    private volatile AtomicBoolean doneLock = new AtomicBoolean(false);
    protected final AtomicInteger progress = new AtomicInteger(0);

    public CancelableTask() {
    }

    @Override
    public final void run() {
        try {
            runUnsafe();
        } catch (Exception e) {
            Config.getLog().i("CancelableTask threw an exception", e);          
        }
    }

    public final void runUnsafe() throws Exception {
//      Config.getLog().d("Running cancelable task: " + toString());
        notifyObservers(this);
        isStarted = true;
        try {
            if (!isCanceled) {
                runImpl();
            }
        } catch (Exception e) {
            // Note: Cancel may throw exception
            if (doneLock.compareAndSet(false, true)) {
                this.e = e;
                notifyObservers(this);
                clearObservers();
                // Someone else should do something with the exception
//              Config.getLog().i("Failed cancelable task: " + toString(), e);
                throw e;
            }
            // Cancel got to the lock first but may NOT have yet changed the cancel flag.
            // Must throw cancellation exception.
        }
        if (doneLock.compareAndSet(false, true)) {
            isSuccess = true;
            progress.set(100);
            notifyObservers(this);
            clearObservers();
//          Config.getLog().d("Finished cancelable task: " + toString());
            return;
        }

        // The task was canceled but the isCanceled may not have been set yet.

        synchronized (doneLock) { // Waiting for the cancel to finish it's logic
        }

//      assert isCanceled; // Commented out because android crashes the app in assertion 
        // No need to notify here because cancel was already notified in
        // cancel method.
        // notifyObservers(this);
//      Config.getLog().d("Already canceled task: " + toString());
        throw new CancellationException("Canceled while running!");
    }

    protected abstract void runImpl() throws Exception;

    protected void cancelImpl() {}

    public final void cancel() {
        synchronized (doneLock) {
            if (doneLock.compareAndSet(false, true)) {
//              Config.getLog().i("Canceling cancelable task: " + toString());
                isCanceled = true;

                cancelImpl();

                notifyObservers(this);

                clearObservers();
            }
        }
    }

    public final boolean isCanceled() {
        return isCanceled;
    }

    public final boolean isSuccessful() {
        return isSuccess;
    }

    public final boolean isDone() {
        return doneLock.get();
    }

    public final boolean isStarted() {
        return isStarted;
    }

    public final Exception getError() {
        return e;
    }

    public int getProgress() {
        return progress.get();
    }

    /**
     * Observers will be cleared after the task is done but only after all of them are notified.
     */
    @Override
    public void addObserver(Observer<CancelableTask> observer) {
        super.addObserver(observer);
    }


//  protected void incrementProgress(int value) {
//      progress += value;
//  }
}

还有CancelableCollection:

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map.Entry;
import java.util.concurrent.CancellationException;

public class CancelableCollection extends CancelableTask {
    private LinkedHashMap<CancelableTask, Integer> cancelables = new LinkedHashMap<CancelableTask, Integer>();
    private volatile boolean normalizing;
    private volatile State state = new State(null, 0, 0);
    private boolean isOneFailsAll = true;

//  public boolean isOneFailsAll() {
//      return isOneFailsAll;
//  }

    public void setOneFailsAll(boolean isOneFailsAll) {
        this.isOneFailsAll = isOneFailsAll;
    }

    public int getTotalWeight() {
        Collection<Integer> values = cancelables.values();
        int total = 0;
        for (int weight : values) {
            total += weight;
        }
        return total;
    }

    /**
     * Adds and runs the cancelable
     * 
     * @param cancelable
     * @return
     * @throws Exception
     *             if failed while running
     * @throws CancellationException
     *             if already canceled
     */
    public void add(CancelableTask cancelable, int relativeTime) {
        if (cancelable == null) {
            return;
        }
        cancelables.put(cancelable, relativeTime);

        if (isCanceled()) {
            throw new CancellationException("Canceled while running!");
        }

        if (isDone()) {
            throw new RuntimeException(
                    "Cannot add tasks if the Cancelable collection is done running");
        }

        if (normalizing) {
            throw new RuntimeException(
                    "Cannot add tasks if already started normalizing");
        }
    }

    @Override
    protected void runImpl() throws Exception {
        normalizeProgress();
        for (Entry<CancelableTask, Integer> entry : cancelables.entrySet()) {
            int currentRelativeTime = entry.getValue();
            CancelableTask currentTask = entry.getKey();
            // Advance the state to the next one with the progress from the
            // previous one.
            state = new State(currentTask, currentRelativeTime, state.getProgress());
            try {
                currentTask.runUnsafe();
            } catch (Exception e) {
                if (isOneFailsAll) {
                    throw e;
                }
                Config.getLog().i("Task failed but continueing with other tasks", e);
            }
        }
        state = new State(null, 0, 100);
    }

    private void normalizeProgress() {
        normalizing = true;
        int overall = 0;
        for (Entry<CancelableTask, Integer> entry : cancelables.entrySet()) {
            overall += entry.getValue();
        }
        double factor = overall == 0 ? 1 : (double)100 / overall;
        for (Entry<CancelableTask, Integer> entry : cancelables.entrySet()) {
            entry.setValue((int) (entry.getValue() * factor));
        }
    }

    @Override
    protected void cancelImpl() {
        for (CancelableTask cancelable : cancelables.keySet()) {
            cancelable.cancel();
        }
    }

    @Override
    public int getProgress() {
        int progress = this.progress.get();
        int stateProgress = state.getProgress();
        this.progress.compareAndSet(progress, stateProgress); // Setting this value just for easier debugging. I has no meaning in CancelableCollection
        return super.getProgress();
    }

    private static class State {
        private CancelableTask currentTask;
        private int currentRelativeTime;
        private int progress;

        public State(CancelableTask currentTask, int currentRelativeTime,
                int progress) {
            super();
            this.currentTask = currentTask;
            this.currentRelativeTime = currentRelativeTime;
            this.progress = progress;
        }

        public int getProgress() {
            return progress
                    + (currentTask == null ? 0 : (int)(currentTask.getProgress()
                            * (double)currentRelativeTime / 100));
        }
    }
}

答案 3 :(得分:-1)

停止线程或asynctask你正在使用或调用this.finish