等待Android中的多个回调

问题描述 投票:4回答:3

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

在其他模型中,我不确定你会怎么做。以RootTools 3.0 Command类为例。你创建了一个Command,有三种方法,commandOutputcommandFinishedcommandTerminated,虽然你可以使用回调在进程结束时做一些事情,但我不知道你将如何等待多个进程(例如,通过列出几个目录并总结文件大小)。

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

java android multithreading asynchronous wait
3个回答
2
投票

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

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

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

当您为命令关闭处理程序并调用wait()时,该命令将在完成后调用notifyAll(),以便您的线程将恢复。

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


1
投票

介绍

我之前的一个项目已经完成了这个主题,并找到了解决问题的不同解决方案(我最终使用方法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;
        }
    }

}

Sample

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

Sample

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

优点 并行执行有时可以节省时间

Sample

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;
        }
    }
}

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() { ... }
}
© www.soinside.com 2019 - 2024. All rights reserved.