2014-02-18 46 views
0

我是线程新手。我搜索了许多与我的问题有关的问题,但我无法为我找到合适的解决方案。我正在做的是我正在使用四个异步任务来使用THREAD_POOL_EXECUTOR从四个不同的社交媒体中获取数据。代码如下: 等待线程池完成执行

new Fb().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 
new Twitter().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 
... 

mAdapter = new MyAdapter(getActivity(), 
       (ArrayList<Model>) showList); 
mListView.setAdapter(mAdapter); 

我希望调用是并行的,以节省获取数据的时间。现在我的想法是,我希望所有四个线程完成工作,然后我想按照时间戳显示排序后的数据。现在问题是我的setAdapter在四个线程完成抓取数据之前被调用,因为在UI线程上设置了适配器。我想要一个机制来阻塞UI线程,直到所有四个线程完成获取数据。

我发现,也许我可以用shutdown()和ExecutorService的的awaitTermination()方法。无论如何,任何人都可以帮助我,这将是非常棒的。非常感谢

+0

你说得对。关闭或等待终止。如果要创建多个线程,还可以扩展线程类并创建自己的线程消息并重新使用相同的线程。也许java优化线程创建与持久线程,以避免创建的开销,所以使用executor可以有效地awaitTermination。 –

+0

如果我正确理解AsyncTask的onPostExecute(Result)应该可以解决你的问题。一旦AsyncTask完成,它会在UI线程上调用onPostExecute。如果所有任务都已完成,您可以保留一个计数器,并且一旦完成,您可以在onPostExecute(Result)函数的列表视图中设置适配器。 –

+0

是的,我做了类似的实现。谢谢你的帮助:) – Sagar

回答

1

我会做的是:

  1. 在您的活动创建一个空的ArrayList
  2. 通行证此ArrayList你的适配器和设置您的ListView适配器。 setAdapter方法不会影响listView - 它仍然是空的,因为列表是空的。
  3. 启动4个AsyncTasks并获取数据。在onPostExecute()中,将此数据添加到ArrayList并调用适配器上的notifyDatasetChanged()。

,因为它是错误的,不应阻止一个UI线程。当您想要立刻显示所有数据时,您可以制作一个简单的计数器,只需在计数器为4时在每个onPostExecute中制作计数器++并调用notifyDatasetChange()。

+0

这是正确的方法。阻止任何UI线程是一个非常糟糕的主意。充其量,它会让你的应用看起来很丑,因为所有东西都保持锁定状态。最糟糕的是,你会得到一个ANR错误。或者,您可以在每次完成适配器时更新适配器,并在适配器上调用'notifyDatasetChanged()',以便更快地将信息更新为用户。 – DeeV

+0

好的我明白了。我不应该想到阻止UI线程。你们都是对的。我试着按@Mark的方式告诉。 Bt发生了什么事是我在创建时间的基础上对数据frm facebook twitter等进行排序。因此,首先任何线程的数据都将frm设置为其postExecute(),然后其他线程完成工作,并在排序所有数据后设置数据。所以新的数据被添加到notifyDatasetChange(),看起来有些模糊。所以我一直在想另一种方式,即1)在所有线程完成执行后才打印数据,2)对它们进行排序3)仅将适配器设置为最终数据一次 – Sagar

+0

您可以按我告诉过的来做。设置适配器,在每个onPostExecute()添加数据到列表中启动所有任务并创建counter ++。创建一个方法来检查计数器是否为4,对列表进行排序并使用notifyDatasetChanged(您也可以在此处设置适配器,应该没有更大的区别)。 – Mark

0

如果你与阻塞UI线程真的好吗,试试这个:

new Fb().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 
new Twitter().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 
... 

AsyncTask.THREAD_POOL_EXECUTOR.shutdown(); 

while (!AsyncTask.THREAD_POOL_EXECUTOR.isTerminated()) {} 

mAdapter = new MyAdapter(getActivity(), 
       (ArrayList<Model>) showList); 
mListView.setAdapter(mAdapter); 

在大多数情况下,虽然,阻塞UI线程不是一个好主意。

+0

好的谢谢你的想法。我会尝试你的代码:) yeaa我也同意阻止UI线程nt是一个好主意..不管怎么说,我很感谢你的支持 – Sagar

+0

AsyncTask.THREAD_POOL_EXECUTOR不包含方法关闭和isTerminated。它们来自ExecutorService。 – Sagar

+0

哎呀,我推测AsyncTask.THREAD_POOL_EXECUTOR是一个ExecutorService。尽管上面的代码不一定有效,但您也许可以创建自己的ExecutorService来执行类似的操作。看起来你已经接受了答案。 – benjammin

0

我可以成功处理该问题,而无需深入研究线程。我使用了执行每个线程后使布尔值为真的简单概念。而在UI线程我检查infinte时间即

while(true) 
{ 
    if(flag1 && flag2 && flag3 && flag4) 
    { 
     //set the adapter and make the flags false 
     break; 
    } 

} 

不要忘记将falgs假执行,否则将继续无限期的时间。