如何填充巨大的TableLayout而不引起超时ARN?

问题描述 投票:0回答:1

我有一个带有数百个表行的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线程中。但是问题是...

android multithreading tablelayout android-anr-dialog
1个回答
0
投票

您无法在后台线程上创建和操作UI元素(TableRowTextView等)。所有这些工作都需要直接在主(UI)线程上完成。您可能正在UI框架的阻塞主(UI)线程并导致您的ANR的部分上创建对象锁。

© www.soinside.com 2019 - 2024. All rights reserved.