我有一个带有数百个表行的TableLayout。
我正在用线程填充它,当创建行时,该线程会通知处理程序,并且处理程序将行添加到UI线程中。但是问题在于,在某些情况下,某些用户会由于以下原因报告ARN:
输入分派超时(正在等待发送键事件,因为焦点窗口尚未完成所有输入事件的处理之前已交付给它。出站队列长度:0。等待队列长度:1。)
当Android OS检测到UI / Main线程已阻塞5秒钟时,它会处理ANR的创建。
我以为使用了AsyncTask,但在Android 11中将不推荐使用。
这是我的主题:
private class PopulateTableThread extends Thread { private Context context; private ArrayList<Player> players; public PopulateTableThread(Context context, ArrayList<Player> players) { super(); this.context = context; this.players = players; } public void run() { for (int i=0; i<players.size(); i++) { TableRow row = new TableRow(context); row.setLayoutParams(rowParams); row.setBackgroundResource(R.drawable.table_row_not_selected); String strings[] = {players.get(i).getName(), "" + players.get(i).getTeam().getName(), "" + players.get(i).getPositionInString(context), "" + players.get(i).getYearsOfContractFormatted(), "" + players.get(i).getValue() + " M€", "" + players.get(i).getSalary() + " M€", "" + players.get(i).getAge(), "" + players.get(i).getBaseLevel()}; for (int j = 0; j < strings.length; j++) { TextView text = new TextView(context); text.setBackgroundResource(R.drawable.table_cell_background); if (j == 0) { text.setLayoutParams(nameParams); text.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); text.setPadding((int) getResources().getDimension(R.dimen.spacing_small), 0, (int) getResources().getDimension(R.dimen.spacing_small), 0); text.setMaxLines(1); text.setEllipsize(TextUtils.TruncateAt.END); }else if (j == 1) { text.setLayoutParams(teamNameParams); text.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); text.setPadding((int) getResources().getDimension(R.dimen.spacing_small), 0, (int) getResources().getDimension(R.dimen.spacing_small), 0); text.setMaxLines(1); text.setEllipsize(TextUtils.TruncateAt.END); } else if (j == 2 || j == 3) { text.setLayoutParams(positionAndContractParams); text.setGravity(Gravity.CENTER); } else if (j == 4) { text.setLayoutParams(valueParams); text.setGravity(Gravity.CENTER); } else if (j == 5) { text.setLayoutParams(salaryParams); text.setGravity(Gravity.CENTER); } else if (j == 6 || j == 7) { text.setLayoutParams(ageAndLevelParams); text.setGravity(Gravity.CENTER); } if (j == 3 && strings[3].split("/")[0].equals("1")) { text.setBackgroundResource(R.drawable.table_cell_background_danger); } text.setMinHeight((int) getResources().getDimension(R.dimen.cell_height)); text.setText(strings[j]); row.addView(text); } ProgressBar levelProgress = new ProgressBar(new ContextThemeWrapper(context, R.style.ProgressBar), null, 0); levelProgress.setBackgroundResource(R.drawable.table_cell_background); levelProgress.setLayoutParams(levelBarParams); levelProgress.setMinimumHeight((int) getResources().getDimension(R.dimen.cell_height)); levelProgress.setProgress(players.get(i).getBaseLevel()); levelProgress.setPadding((int) getResources().getDimension(R.dimen.spacing_small), 0, (int) getResources().getDimension(R.dimen.spacing_small), 0); row.addView(levelProgress); final int finalIndex = i; row.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (searchProgressBar.getVisibility() == View.VISIBLE) { return; } SoundEffectsManager.getInstance().play(context, SoundEffectsManager.button); displaySignDialog(players.get(finalIndex)); } }); Message message = new Message(); message.what = HANDLER_ROW_CREATED; message.obj = row; updateTableHandler.sendMessage(message); } Message message = new Message(); message.what = HANDLER_TABLE_FILLED; updateTableHandler.sendMessage(message); } }
这是当线程创建新TableRow时正在更新ui线程的处理程序:
updateTableHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what){ case HANDLER_ROW_CREATED: TableRow row = (TableRow) msg.obj; tableLayout.addView(row); break; case HANDLER_TABLE_FILLED: tableLayout.setAlpha(1f); searchProgressBar.setVisibility(View.GONE); break; } } };
如何避免这些ARN报告?
我有一个带有数百个表行的TableLayout。我用一个线程填充它,该线程在创建行时通知处理程序,并且处理程序将行添加到UI线程中。但是问题是...
您无法在后台线程上创建和操作UI元素(TableRow
,TextView
等)。所有这些工作都需要直接在主(UI)线程上完成。您可能正在UI框架的阻塞主(UI)线程并导致您的ANR的部分上创建对象锁。