我正在开发一个 Android 应用程序,并且我有一个 Activity,我在其上显示两个 TableLayout 的顶部。第一个 TableLayout 包含一个比赛的记分牌(类型 1),第二个是另一个比赛的记分牌(类型 2)。
我从同一个 XML 布局文件中扩充了这两个 TableLayout。我用来自 doInBackground() (AsyncTask) 的数据填充它们。但是,填充部分非常繁重,因此我将其放入自定义同步方法(在 AsyncTask 类中)并将膨胀的 TableLayout 对象作为参数传递给该方法。
我使用 ExecutorService 对象从 doInBackground() 方法调用所述方法。这个 ExecutorService 对象是用 Executors.newSingleThreadExecutor() 创建的。我将第一个方法调用放在一个 Runnable 中,将第二个方法调用放在另一个 Runnable 中,并在这些可运行对象上触发 ExecutorService.execute()。
在该方法中,我通过在传入的 TableLayout 对象参数上调用 findViewById() 并在这些视图上调用 TextView.setText() 等方法来访问 UI 元素。这在大多数情况下都可以正常工作,但我开始看到一些例外情况,例如
ERROR/AndroidRuntime(409): FATAL EXCEPTION: pool-9-thread-1
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
和
ERROR/AndroidRuntime(378): FATAL EXCEPTION: pool-2-thread-1
java.lang.NullPointerException
这让我相信我必须以难以置信的倒退来做这件事。我将在下面包含一个简化的代码片段,以帮助描述我目前正在做的事情:
class AddRacesTask extends AsyncTask<Void, View, Void> {
synchronized void populateTable(ArrayList<Race> data, TableLayout table) {
TextView headerText = table.findViewById(R.id...);
headerText.setText("Header");
for(Race race : data) {
TableRow row = getLayoutInflater().inflate(R.layout....);
TextView pos = row.findViewById(R.id....);
pos.setText(race.getPos());
TextView person = row.findViewById(R.id....);
person.setText(race.getPerson());
// etc.
// etc..
// etc...
table.addView(row);
}
publishProgress(table);
}
@Override
private Void doInBackground(Void... voids) {
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(new Runnable() {
@Override
public void run() {
TableLayout raceType1Layout = getLayoutInflater().inflate(R.layout...);
populateTable(data, raceType1Layout);
}
});
executor.execute(new Runnable() {
@Override
public void run() {
TableLayout raceType2Layout = getLayoutInflater().inflate(R.layout...);
populateTable(data, raceType1Layout);
}
});
}
@Override
protected void onProgressUpdate(View... values) {
if(values[0] instanceof TableLayout) {
container.addView(values[0]);
}
}
}
我欢迎任何反馈。此外,如果您需要更多内容,我很乐意发布我的实际源代码,但我认为简化和干净的版本会更容易。