有什么方法可以在Android上并行创建视图?

时间:2020-02-02 21:49:55

标签: java android threadpoolexecutor

我正在开发一个应用程序,在执行的某个部分中,用户将能够以图形形式查看文本文件中的数据。但是,由于文本文件可以有几列(并且打算为每列创建一个图形),因此仅使用UI线程可能会阻塞应用程序一段时间。所以我的问题是:Android上是否有任何类可以让我并行创建这些图(View s,并在所有图准备好后将它们添加到父级布局中?

我的第一个想法是按如下方式使用ExecutorService(为简单起见,使用TextView而不是GraphView是我正在使用的库中的类项目):

  • createTextsInParallel实现:
public void createTextsInParallel(){
    ExecutorService executor = (ExecutorService) Executors.newFixedThreadPool(3);

    List<TextBuilderTask> taskList = new ArrayList<>();
    for (int i = 0; i < arrays.size(); i++){    // arrays is an ArrayList<ArrayList<Double>>
        if (arrays.get(i) == null) continue;
        taskList.add(new TextBuilderTask(this, arrays.get(i), i));
    }

    List<Future<TextView>> futureList = null;
    try {
        futureList = executor.invokeAll(taskList);

    } catch (InterruptedException e){
        e.printStackTrace();
    }

    executor.shutdown();

    if (futureList != null){
        for (int i = 0; i < futureList.size(); i++){
            TextView tv = futureList.get(i).get();
            parentLayout.addView(tv);           // parentLayout is a LinearLayout 
        }
    }
}
  • TextBuilderTask实现:
class TextBuilderTask implements Callable<TextView> {
    protected MyActivity activity;
    protected ArrayList<Double> array;
    protected int pos;

    public TextBuilderTask(MyActivity activity, ArrayList<Double> array, int pos){
        this.activity = activity;
        this.array = array;
        this.pos = pos;
    }

    @Override
    public TextView call() throws Exception {
        TextView tv = new TextView(this.activity);
        tv.setText(String.format("%d: %s", this.pos, Arrays.toString(this.array)));
        return tv;
    }
}

但是上面的方法抛出以下异常:

Caused by: java.lang.RuntimeException: Can't create handler inside thread Thread[pool-1-thread-1,5,main] that has not called Looper.prepare()

那我应该在哪里打电话Looper.prepare()?基于先前的SO问题,每当我致电Looper.prepare()时,我也应同时致电Looper.loop()Looper.quit()。但是由于我使用ExecutorService来完成这项工作,所以我不确定应该在哪里给他们打电话。任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:1)

我无法运行您的代码,因为它包含一些错误并且无法立即编译,但是我怀疑问题出在以下事实:您在辅助线程中实例化了视图(即调用{ {1}})。 我知道这正是您的目标,但这可能不是一个好主意,因为它取决于您要实例化的View的实现。例如,如果其构造函数创建了一些处理程序,则将需要准备循环程序。 您可以尝试使用call()方法来执行此操作,但是仍然存在一个事实,那就是此时,其处理程序可能正在意外线程上运行。

它似乎也是特定于平台的,因此它可能在某些手机上运行而不在其他手机上运行,​​具体取决于该特定View的实际实现。我建议在这里看看这篇文章,也许您可​​以尝试遵循其中一些建议(例如,使用AsyncLayoutInflater): Inflate a view in a background thread