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

Is there any way to create views on Android in parallel?

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

我的第一个想法是使用 ExecutorService 如下(为了简单起见,使用 TextView 而不是 GraphView,class 来自一个库我在我的项目中使用):

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 
        }
    }
}
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 来完成这项工作,所以我不确定应该在哪里给他们打电话。感谢任何帮助。

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

它似乎也是特定于平台的,因此它可能适用于某些手机而不适用于其他手机,具体取决于特定视图的实际实现。我建议在此处查看此 post,也许您可​​以尝试遵循其中一些建议(例如使用 AsyncLayoutInflater): Inflate a view in a background thread