等待Android中的多个回调

时间:2013-07-02 05:46:02

标签: java android multithreading asynchronous wait

在Java线程中,您可以在列表中包含一些线程,启动它们,然后使用主线程join,然后执行另一个线程,等待所有进程完成后再继续。

在其他型号中,我不确定你会怎么做。以RootTools 3.0 Command类为例。您创建的Command有三种方法,commandOutputcommandFinishedcommandTerminated,虽然您可以使用回调在流程结束时执行某些操作,但我不会我不知道你将如何等待多个进程(例如,浏览几个目录的列表并总结文件大小)。

我相信Android Asynctask会有类似的问题 - 你可以很容易地进行回调,但是没有办法等待几个任务。除非我错过了什么?

3 个答案:

答案 0 :(得分:2)

您可以对正在执行的命令调用wait()。

虽然在执行此操作之前,您应该关闭您调用wait的命令的处理程序。您可以通过将RootTools.handlerEnabled设置为false或在每个单独的命令中使用构造函数并传入false来禁用该命令的处理程序来为每个命令执行此操作。

这很重要,因为如果使用了处理程序,那么它将尝试在你调用wait()的线程上调用回调方法,这将导致死锁。

当你为命令关闭处理程序并调用wait()时,命令会在完成后调用notifyAll(),这样你的线程就会恢复。

这方面的负面影响是,回调方法将不再在您正在处理的线程中完成,因此除非您实现处理程序或其他可接受的处理程序,否则您将无法使用这些回调方法执行任何UI工作处理这个的解决方案。

答案 1 :(得分:0)

使用CountDownLatch,我会在这里复制他们的用法示例以获得更好的语法突出显示(:

class Driver { // ...
  void main() throws InterruptedException {
    CountDownLatch startSignal = new CountDownLatch(1);
    CountDownLatch doneSignal = new CountDownLatch(N);

    for (int i = 0; i < N; ++i) // create and start threads
      new Thread(new Worker(startSignal, doneSignal)).start();

    doSomethingElse();            // don't let run yet
    startSignal.countDown();      // let all threads proceed
    doSomethingElse();
    doneSignal.await();           // wait for all to finish
  }
}

class Worker implements Runnable {
  private final CountDownLatch startSignal;
  private final CountDownLatch doneSignal;
  Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
    this.startSignal = startSignal;
    this.doneSignal = doneSignal;
  }
  public void run() {
    try {
      startSignal.await();
      doWork();
      doneSignal.countDown();
    } catch (InterruptedException ex) {} // return;
  }

  void doWork() { ... }
}

答案 2 :(得分:0)

简介

我在上一个项目中浏览了该主题,并找到了解决该问题的不同方法(我最终在项目中使用了方法1,因为它最适合该方法)。我将与您尽可能简单地分享它们。为了更好地理解,我将以下载多个图像的示例为例进行解释。

ImageDownloader成为从URL异步下载图像的类,它具有以下属性。

  • 接口-ImageDownloadCallback,用于在任务完成时获取回调。它有两种方法
    • void onSuccess(String imagePath):任务成功完成时调用。
    • void onFailure():在任务未能完成时调用。
  • 一种方法-download(String url, ImageDownloadCallback callback)启动下载任务

PauseModeCallbackHandlerChainModeCallbackHandlerParallelModeCallbackHandler分别是这三种方法的回调的包装器类。您可以根据要执行的任务对其进行自定义。




方法1:

通过暂停启动线程一个接一个地执行任务。

Illustration of solution 1

专业人士
在原始线程中获取结果

缺点
需要让线程等待


ThreadLockedTask

您可以使用此类使线程等待直到获得结果。

import java.util.concurrent.atomic.AtomicReference;

/**
 * @author Ahamad Anees P.A
 * @version 1.0
 * @param <T> type
 */
public class ThreadLockedTask<T> {

    private AtomicReference<ResultWrapper<T>> mReference;

    public ThreadLockedTask() {
        mReference = new AtomicReference<>(new ResultWrapper<T>());
    }

    public T execute(Runnable runnable) {
        runnable.run();
        if (!mReference.get().mIsSet)
            lockUntilSet();
        return mReference.get().mResult;
    }

    private void lockUntilSet() {
        synchronized (this) {
            while (!mReference.get().isSet()) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    public void setResult(T result) {
        synchronized (this) {
            ResultWrapper<T> wrapper = mReference.get();
            wrapper.setResult(result);
            wrapper.setIsSet(true);
            notify();
        }
    }

    public static class ResultWrapper<T> {
        private boolean mIsSet;
        private T mResult;

        public boolean isSet() {
            return mIsSet;
        }

        public T getResult() {
            return mResult;
        }

        void setIsSet(boolean isCompleted) {
            this.mIsSet = isCompleted;
        }

        void setResult(T result) {
            this.mResult = result;
        }
    }

}


样本

import java.util.ArrayList;
import java.util.List;

public class PauseModeCallbackHandler {

    // List of results
    private static List<String> results;

    public static void start(final List<String> urls, final ImageDownloader.ProgressUpdateListener listener) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                results = new ArrayList<>();

                // Do tasks one by one
                for (final String url :
                        urls) {

                    //Here the result is a String. Change "String" in the following two lines for other datatypes.
                    final ThreadLockedTask<String> task = new ThreadLockedTask<>();
                    final String imagePath = task.execute(new Runnable() {
                        @Override
                        public void run() {
                            //Start the task here
                            ImageDownloader.getInstance(listener).download(url,
                                    new ImageDownloader.ImageDownloadCallback() {
                                        @Override
                                        public void onSuccess(String imagePath) {
                                            //Set the result on success
                                            task.setResult(imagePath);
                                        }

                                        @Override
                                        public void onFailure() {
                                            //Set result as null on failure
                                            task.setResult(null);
                                        }
                                    });
                        }
                    });

                    if (imagePath!=null)
                        results.add(imagePath);

                }

                afterCallbacks();
            }
        }).start();
    }

    private PauseModeCallbackHandler() {}

    private static void afterCallbacks() {
        // All tasks completed. List "results" now holds the result

        DemoActivity.isTasksInProgress = false;
    }
}




方法2:

从上一个回调中执行任务,就像连锁反应一样。

Illustration of solution 2


样本

import java.util.ArrayList;
import java.util.List;

public class ChainModeCallbackHandler implements ImageDownloader.ImageDownloadCallback {

    // List of args to start the task. Use pojo classes if your task has multiple args
    private static List<String> urls;

    // List of results
    private static List<String> results;

    // Optional.
    private static ImageDownloader.ProgressUpdateListener progressUpdateListener;

    // Leave it as it is
    private int index;

    public static void start(List<String> urls, ImageDownloader.ProgressUpdateListener listener) {
        ChainModeCallbackHandler.urls = urls;
        results = new ArrayList<>();
        progressUpdateListener = listener;

        //Start with the first task
        ImageDownloader.getInstance(listener).download(urls.get(0), new ChainModeCallbackHandler(0));
    }

    private ChainModeCallbackHandler(int index) {
        this.index = index;
    }

    @Override
    public void onSuccess(String imagePath) {
        results.add(imagePath);
        afterCallback();
    }

    @Override
    public void onFailure() {
        afterCallback();
    }

    private void afterCallback() {
        int nextIndex = index+1;
        if (nextIndex<urls.size()) {
            //Tasks are not completed yet. Do next task
            ImageDownloader.getInstance(progressUpdateListener).download(urls.get(nextIndex),
                    new ChainModeCallbackHandler(nextIndex));
        } else {
            // All tasks completed. List "results" now holds the result

            DemoActivity.isTasksInProgress = false;
        }
    }
}




方法3:

并行执行任务。

Illustration of solution 3

专业人士
并行执行有时可以节省时间


样本

import java.util.ArrayList;
import java.util.List;

public class ParallelModeCallbackHandler {

    // List of args to start the task. Use pojo classes if your task has multiple args
    private static List<String> urls;

    // List of results
    private static List<String> results;

    // Leave it as it is
    private static int count;

    public static void start(List<String> urls, ImageDownloader.ProgressUpdateListener listener) {
        ParallelModeCallbackHandler.urls = urls;
        results = new ArrayList<>();
        count = 0;

        // Start all tasks
        for (String url :
                urls) {
            //Replace with your task and its callback
            ImageDownloader.getInstance(listener).download(url, new ImageDownloader.ImageDownloadCallback() {
                @Override
                public void onSuccess(String imagePath) {
                    results.add(imagePath);
                    afterCallback();
                }

                @Override
                public void onFailure() {
                    afterCallback();
                }
            });
        }
    }

    private ParallelModeCallbackHandler() {}

    private static void afterCallback() {
        if (++count==urls.size()) {
            // All tasks completed. List "results" now holds the result

            DemoActivity.isTasksInProgress = false;
        }
    }
}