【问题标题】:Android ProgressBar not updating as expected?Android ProgressBar 没有按预期更新?
【发布时间】:2014-05-31 05:18:18
【问题描述】:

我正在使用 AsyncTask 动态填充 TableLayout 行,但没有得到预期的 ProgressBar 行为。

我最初将ProgressBar 的最大值设置为我正在处理的项目数的三倍以适应三个操作。这是我的代码:

onPreExecute:

        progress.setMax(items.size() * 3); // We need to create the rows and add listeners to them

异步类

public class TableLoader extends AsyncTask<Object, String, Boolean>{

    @Override
    protected Boolean doInBackground(Object... params) {

    for (int i = 0; i < items.size(); i++) {
            // doStuffToCreateRow
            rows.add(row);

        progress.publishProgress();
    }
}

那么我有:

@Override
protected void onPostExecute(Boolean result) {
    super.onPostExecute(result);

    if (!isCancelled()) {
        for (int i = 0; i < rows.size(); i++) {
            table.addView(rows.get(i));
            progress.incrementProgressBy(1);
        }

        table.requestLayout();  

        listener.onTaskCompleted();
    }
}

publishProgress 很简单:

protected void onProgressUpdate(String... values) {
  progress.incrementProgressBy(1);
}

最后,在我的onPostExecute method 中,我对使用AsyncTask 的活动进行了回调,在主活动中如下所示:

public void onTaskCompleted() { // TableRows have been generated
    TableLayout itemTable = (TableLayout) findViewById(R.id.itemTable);

    for (int i = 0; i < itemTable.getChildCount(); i++) {
        TableRow row = (TableRow) itemTable.getChildAt(i);
                    // Create and add a listener to that row's checkbox
                    // progress.incrementProgressBy(1);
    }
            progress.setVisibility(View.GONE);
}

由于某种原因,初始增量正常工作并导致progressBar 在完成(生成 TableRows)后达到 1/3。之后,有 2-5 秒的暂停,UI 线程阻塞,然后 progressBar 消失,我已将其设置为在 onTaskCompleted(第三个也是最后一个操作)中的 for 循环终止后发生。然后显示数据。

为什么我的progressBar 没有按预期更新?

我查看了问题,但发现人们使用除法或不使用 UI 线程将条形增加

【问题讨论】:

    标签: android multithreading android-asynctask tablelayout android-progressbar


    【解决方案1】:

    由于某种原因,初始增量正常工作并导致进度条在完成后达到 1/3 满

    这意味着异步部分工作正常,您的前三分之一是涉及 doInBackground / ProgressUpdate 的部分,也就是说,在 UI 线程之外完成了繁重的工作,只是发出进度更新的信号。 UI 线程正在休眠并愉快地等待更新请求。

    之后,有 2-5 秒的暂停,其中 UI 线程阻塞,然后 progressBar 消失,我已将其设置为在 onTaskCompleted 中的 for 循环(第三个也是最后一个操作)终止后发生.然后显示数据。

    另外两个操作发生在 UI 线程中。 onPostExecutedonTaskCompleted 中的 for 都在 UI 线程上运行,并且是紧密循环。 UI 线程在您的循环中被阻塞。因此,当您处于这些紧密循环中时,无论您与任何 UI 组件混合数千次:setprogress、settext 等...... 它不会更新,直到 for 循环结束,您的例程完成,系统再次控制 UI 线程。

    您可以做的是,因为看起来有很多行,所以将它们分块添加,然后更新进度。这会给人一些空气。看看下面的原型

     Handler handler=new Handler();
    
     interface AddRowListener {
          public void onRowsAdded();
     }
    
     private void addRowChunk(final int startRow, final int totalRows, final AddRowListener listener) {
    
              for (int i=startRow; i<startRow+CHUNK_SIZE; i++) {
    
                   if (i>=totalRows) {
                        // we have finished! Just call the listener
                        listener.onRowsAdded();
                        return; 
                   }
                   addView....
              }
    
              // After adding some rows, we end here, and schedule a call to this function again
              // to continue. The 25ms delay is optional, but it will give some air to Android for sure
    
              handler.postDelayed(new Runnable() {
                    addRowChunk(startRow+CHUNK_SIZE, totalRows, listener);
              }, 25);
     }
    
     private void addRows(AddRowListener listener) {
    
          TableLayout itemTable = (TableLayout) findViewById(R.id.itemTable);
    
          // we start the process, it will create row chunks and call the listener when done
          addRowChunk (0, itemTable.getChildCount(), listener); 
     }
    

    所以要添加你现在可以做的行:

     addRows (new AddRowListener() {
           public void onRowsAdded() {
    
               // the rows have been added.
    
           }
     });
    

    顺便问一下,你的行大小是多少?它必须是巨大的!

    PD_ 你必须选择一个 CHUNK_SIZE。只需对值进行试验,直到 UI 变得活泼。我会说 40-50 是可以的,但这只是一个疯狂的猜测,取决于手机硬件。

    【讨论】:

    • 我明白了 - 如果我理解正确的话,即使我将更新添加到处理单个行的循环内的 progressBar,在 UI 线程完成之前我仍然不会看到更新与 for 循环。也就是说,根本没有。我可以简单地运行两个 for 循环,其中外循环将操作分成多个步骤,而内循环处理每一行的代码吗?我可以将 progressBar 更新放在内部循环之外。
    • 你应该这样做,但是为了有效地拆分操作,你应该以某种方式将控制权返回给 UI 线程(否则你只会重组你的算法,但它也会劫持 UI 线程) .我正在用原型扩展答案。
    • 我理解你在概念上的建议,但我还不确定我会如何做这样的事情。原型会很棒!感谢您的帮助!
    • 关键概念是:如果 UI 线程在 UI 线程上运行,则 UI 不会“在您的例程中间”更新。
    • 如果我完成了,我不需要一些检查来阻止 handler.postDelayed 调用吗?理论上,我的行大小可以达到数千 - 这太疯狂了!这绝对不是预期的用例,但由于应用程序的性质,我想确保它是密封的。我会对此进行测试并回复您!谢谢!
    【解决方案2】:

    不要将progress.setMax() 设置在doInBackground() 中,而是在onPreExecute() 中设置。您不应该从工作线程/后台线程修改 UI 线程(主线程),而 doInBackground() 正是在哪里运行的。 onPreExecute()onProgressUpdate()onPostExecute() 在 UI 线程上运行。

    【讨论】:

    • 我已经调整了我的代码来解决这个问题,但它没有解决 ProgressBar 加载的问题,直到 1/3,冻结,然后随着三个步骤完成而消失。这似乎不能解决我的问题。
    • 发生这种情况时您的日志输出是什么?
    • 我自己目前没有明确使用日志。你想让我检查什么?
    • 顺便问一下,progress.publishProgress() 是什么? progress 是你的进度条,不是吗?
    • 正确 - publishProgress() 只包含“progress.incrementProgressBy(1);”
    【解决方案3】:

    为什么你不使用线程来更新进度条。这种方法非常适合更新进度........但是如果您想手动设置,则首先设置进度条的最大值只需在 onPreExecute 中调用以下方法,然后在 onPostExecute 中调用 p>

     progressBar.setProgress(value);
    

    当你从 onPreExecute 调用时 Value 应该是最大值的一半,然后从 onPostExecute 调用百分比......但我建议你使用线程来更新正确的进度。

    【讨论】:

    • 这不会造成一个无响应的进度条突然飙升到一半然后又满吗?此外,我在其他地方阅读了很多建议 AsyncTask 用于此类事情的答案,因为它是线程和进度的抽象。它甚至有一个针对这类事情的 onProgressUpdate 方法。你能为这个答案提供一些理由吗?我愿意说服,但我不太确定这是最好的方法。
    • @user3563124 是的,我已经提到这只是一个奇怪的修复,所以我只建议使用线程进行进度更新
    • 使用线程非常糟糕。 AsyncTask 有 publishProgress 女巫可以做所有事情。
    【解决方案4】:

    不要在 onPostExecute 中使用 publishProgress。只需调用 incrementProgressBy。

    【讨论】:

    • 我会试试这个 - 为什么我不应该这样做?此外,最后一组调用(监听器分配)只是调用了 incrementProgressBy,但我没有看到任何积极的变化。为什么更改 onPostExecute 调用会改变这一点?
    • 刚试过这个 - 它似乎没有解决问题。我仍然得到 1/3 条,5 秒的 UI 线程阻塞,然后是一个完整的列表,没有条。
    • 你为什么不把你所有的代码都放在doInBackground中呢?只有在 onPostExecute 中,您才能将新视图附加到它们的父视图。
    • 根据我对 AsyncTask 文档的理解,任何更新 UI 的代码都应该在 UI 线程上执行。从 onPostExecute 运行代码在 UI 线程上运行它。此外,回调用于在特定范围内执行代码,以避免将某些变量传递给 AsyncTask。无论哪种方式,我都不确定将代码放在 doInBackground 中(即使我可以)是否可以解决 progressBar 问题。
    • 只要您只在 doInBackground 中创建视图就可以了。如果您指定了父母,您只能触摸 UI。这就是你在 onPostExecute 中所做的。
    猜你喜欢
    • 1970-01-01
    • 2011-08-28
    • 2020-06-06
    • 1970-01-01
    • 2014-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多