首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >并行运行长作业,只有在所有作业完成后才能更新UI。

并行运行长作业,只有在所有作业完成后才能更新UI。
EN

Stack Overflow用户
提问于 2014-07-23 08:52:02
回答 3查看 278关注 0票数 0

我正在构建一个Android应用程序,我对这个体系结构有一些问题--如何在不同的线程上实现许多调用。

我有两种方法:

代码语言:javascript
复制
ConnectAndGetId() //takes 2-3 seconds
GetTokenID(ID)    //takes 2-3 seconds

首先,我需要调用ConnectAndGetId(),然后在得到一个结果之后,ID调用GetTokenID(ID)。获得tokenID后,我需要调用4个方法并传递给它们tokenID

代码语言:javascript
复制
getNames (tokenID) //takes 4 second
getPhones (tokenID) //takes 7 seconds
getIds(tokenID) //takes 2 seconds
getDetailObject(tokenID) //takes 5 seconds

这样做的目的是在得到来自的ALL 4方法的结果之后,只显示数据。不需要一个一个地执行它们,因为这将花费大量的时间(18秒),我想并行地运行它们,最后用所有的数据来更新UI

我想做下一件事:

启动AsyncTask并调用ConnectAndGetId,在onPostExecute()中启动另一个AsyncTask并在那里运行GetTokenID(ID)。在运行GetTokenID(ID)之后,我将将结果返回给UI线程,使用返回的数据,我将启动4个新的threads,每个线程将调用这4个方法中的一个。我可以计数完成的线程,当我得到所有的4个结果时,我可以用处理程序更新UI

这是正确的做法吗?也许我不应该为4个方法创建4个线程?否则,创建一个handlerThread并将这4个方法传递给他的处理程序,这样线程就会将它们集中起来--但它将是一个接一个的。

这是正确的想法还是可以做得更好?

EN

回答 3

Stack Overflow用户

发布于 2014-07-23 09:11:26

这是正常的方法。但是我建议您使用Executor,而不是创建Threads。示例:

代码语言:javascript
复制
public class TasksSample {
    public static void execute(){
        ExecutorService executorService = Executors.newFixedThreadPool(4);
        executorService.submit(new Task("A"));
        executorService.submit(new Task("B"));
        executorService.submit(new Task("C"));
        executorService.submit(new Task("D"));
        executorService.shutdown();
        try {
            executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("all tasks finished");
    }

    private static class Task implements Runnable{

        private String taskId;

        public Task(String taskId) {
            this.taskId = taskId;
        }

        @Override
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("finished task: " + taskId);
        }
    }
}
票数 1
EN

Stack Overflow用户

发布于 2014-07-23 09:01:15

问题确实很好。我认为您的方法是正确的,但是我不会在onPostExecute()上创建onPostExecute线程。我认为最好是用一个听众来确保你得到了你所需要的结果。在接下来的步骤中,我还将使用一个监听器来调用您的4个方法。

问题是:您是否需要完成这4种方法来更新您的UI?然后,您应该使用一个具有同步块的监听器,该监听器只在4个方法完成时才输入。您可以使用一种方法来检查这些方法是否得到了它们的结果,并且当4完成时,更新UI。

如果您不需要完成更新UI的4个方法,我只需在UI中添加一个ProgressDialog并逐个方法更新它。在最后一个中,取消ProgressDialog并解除UI的阻塞。

我希望它能帮助你,兄弟,祝你在编码方面好运!

票数 0
EN

Stack Overflow用户

发布于 2014-07-23 09:24:42

关于运行四个线程是否适合您的情况,只有您可以判断。它增加了程序的复杂性,需要多线程访问保护和相关数据的同步。还要考虑并行访问是否真的可以加快计算速度。只有当限制因素是单线程计算速度时,并行访问才会加快,如果限制是以数据带宽为限,您将不会看到任何显著的速度增长。

对于四个线程完成一个UI更新的问题,您可以尝试使用CyclicBarrier锁定所有线程,直到最后一个线程完成执行为止。

以下是一个示例:

代码语言:javascript
复制
// Create a CyclicBarrier with 4 parties and a target action to update UI

CyclicBarrier barrier = new CyclicBarrier(4, new Runnable(){
    public void run(){
        //Do your UI updates here (remember any direct UI must be on UI thread)
    } 
});

// Pass above CyclicBarrier to your four threads


// Skeleton of Runnable instance for each of the four threads.

Runnable r = new Runnable(){
    public void run(){
        // Run desired long-running method

        // getNames, getPhones, etc

        // Call await() from CyclicBarrier instance (exception handling not shown)

        barrier.await();
    }
};

使用上面的代码,完成的每个线程都将阻塞等待方法,直到第四个线程调用await()为止,在第四个线程中,所有线程取消阻塞,最后一个线程运行在开始时传递给CyclicBarrier的可运行线程。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24905981

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档