有什么方法可以并行创建 Android 上的视图吗?
Is there any way to create views on Android in parallel?
我正在开发一个应用程序,在执行的某个部分,用户将能够以图形的形式查看文本文件中的数据。但是,由于文本文件可以有多个列(并且它打算为每个列创建一个图表),因此仅使用 UI 线程可能会暂时阻塞应用程序。所以我的问题是:Android 上是否有任何 class 允许我并行创建这些图 (View
s),当所有图都准备好后,将它们添加到父级布局?
我的第一个想法是使用 ExecutorService
如下(为了简单起见,使用 TextView
而不是 GraphView
,class 来自一个库我在我的项目中使用):
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
来完成这项工作,所以我不确定应该在哪里给他们打电话。感谢任何帮助。
我无法 运行 你的代码,因为它包含一些错误并且不会立即编译,但我怀疑问题在于你在辅助线程中实例化了视图(这是调用 call()
的那个)。
我知道这正是您的目标,但这可能不是一个好主意,因为它取决于您正在实例化的视图的实现。例如,如果他们的构造函数创建了一些处理程序,他们将要求准备好循环程序。
您可以尝试在 call()
方法中执行此操作,但事实仍然是,此时它们的处理程序可能 运行 在意外线程上运行。
它似乎也是特定于平台的,因此它可能适用于某些手机而不适用于其他手机,具体取决于特定视图的实际实现。我建议在此处查看此 post,也许您可以尝试遵循其中一些建议(例如使用 AsyncLayoutInflater):
Inflate a view in a background thread
我正在开发一个应用程序,在执行的某个部分,用户将能够以图形的形式查看文本文件中的数据。但是,由于文本文件可以有多个列(并且它打算为每个列创建一个图表),因此仅使用 UI 线程可能会暂时阻塞应用程序。所以我的问题是:Android 上是否有任何 class 允许我并行创建这些图 (View
s),当所有图都准备好后,将它们添加到父级布局?
我的第一个想法是使用 ExecutorService
如下(为了简单起见,使用 TextView
而不是 GraphView
,class 来自一个库我在我的项目中使用):
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
来完成这项工作,所以我不确定应该在哪里给他们打电话。感谢任何帮助。
我无法 运行 你的代码,因为它包含一些错误并且不会立即编译,但我怀疑问题在于你在辅助线程中实例化了视图(这是调用 call()
的那个)。
我知道这正是您的目标,但这可能不是一个好主意,因为它取决于您正在实例化的视图的实现。例如,如果他们的构造函数创建了一些处理程序,他们将要求准备好循环程序。
您可以尝试在 call()
方法中执行此操作,但事实仍然是,此时它们的处理程序可能 运行 在意外线程上运行。
它似乎也是特定于平台的,因此它可能适用于某些手机而不适用于其他手机,具体取决于特定视图的实际实现。我建议在此处查看此 post,也许您可以尝试遵循其中一些建议(例如使用 AsyncLayoutInflater): Inflate a view in a background thread