【问题标题】:How do you clear a determinate progress bar for reuse?您如何清除确定的进度条以供重用?
【发布时间】:2012-06-29 09:37:12
【问题描述】:

我有一个带有一个按钮的 Activity,它可以启动一个长时间运行的任务。我使用 AsyncTask 执行任务并显示一个确定的 ProgressBar,该进度条会随着任务的进行而更新。第一次运行任务时一切正常,但在随后的运行中会出现对话框,但已经处于 100% 和 100/100。我在我的活动中同时覆盖了 onCreateDialog 和 onPrepareDialog。我认为使用 setProgress(0) 会重置对话框,但这不起作用。我在 AsyncTask 的 onPreExecute 方法中使用 showDialog,在 AsyncTask 的 onPostExecute 中使用dismissDialog。我能够重置对话框的唯一方法是在 onPostExecute 中使用 removeDialog,但我宁愿不重新创建对话框,因为我将重复使用多次。相关代码如下。这是 API 级别 10。

@Override
protected Dialog onCreateDialog(int id) {
    switch (id) {
        case PROGRESS_DIALOG:
            progressDialog = new ProgressDialog(ProtoBufSerializationTestActivity.this);
            progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            progressDialog.setCancelable(true);
            progressDialog.setMax(100);
            progressDialog.setMessage("Testing...");
            return progressDialog;
        default:
            return null;
    }
}

@Override
protected void onPrepareDialog(int id, Dialog dialog) {
    super.onPrepareDialog(id, dialog);
    switch (id) {
        case PROGRESS_DIALOG:
            ProgressDialog tmp = (ProgressDialog)dialog;
            tmp.setProgress(0);
            tmp.setSecondaryProgress(0);
            return;
        default:
            Log.e("test", "Unknown dialog requested");
    }
}

private class SerializationTestTask extends AsyncTask<Void, Integer, Long> {

    @Override
    protected void onPreExecute() {
        showDialog(PROGRESS_DIALOG);
    }

    @Override
    protected Long doInBackground(Void... params) {
        long accumulator = 0;
        int totalSize = 0;
        for (int i = 0; i < 10000; i++) {
            final long start = System.nanoTime();
            //code to be timed
            final long end = System.nanoTime();
            accumulator += end - start;
            if (i % 100 == 0) {
                publishProgress(i);
            }
        }
        return accumulator;
    }

    @Override
    protected void onPostExecute(Long aLong) {
        dismissDialog(PROGRESS_DIALOG);
        results.setText(String.format("Serialized Message 10000 times.\nAverage time to serialize %.3fms", (double) aLong / 1e10));
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        progressDialog.incrementProgressBy(1);
    }

编辑在接受@Arhimed 的建议后,我得到了以下代码。它要简单得多。我本可以使用DialogFragment,但我认为在这种情况下没有必要。

private class SerializationTestTask extends AsyncTask<Void, Integer, Long> {
    private ProgressDialog dialog;

    @Override
    protected void onPreExecute() {
        dialog = ProgressDialog.show(ProtoBufSerializationTestActivity.this, "Serialization Test", "Testing...", false);
    }

    @Override
    protected Long doInBackground(Void... params) {
        long accumulator = 0;
        int totalSize = 0;
        for (int i = 0; i < 10000; i++) {
            final long start = System.nanoTime();
            //code to be timed
            final long end = System.nanoTime();
            accumulator += end - start;
            if (i % 100 == 0) {
                publishProgress(i);
            }
        }
        return accumulator;
    }

    @Override
    protected void onPostExecute(Long aLong) {
        dialog.dismiss();
        results.setText(String.format("Serialized Message 10000 times.\nAverage time to serialize %.3fms", (double) aLong / 1e10));
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        dialog.incrementProgressBy(1);
    }
}

【问题讨论】:

    标签: android android-widget android-progressbar


    【解决方案1】:

    实际上,Arhimed 是正确的,你不能这样做,但你可以用“脏”的方式强制进度条进入其零状态。对我来说,客户无论如何都希望进度条将其值归零,以防万一用户离开该活动,但在我的情况下,进度仍然存在,只是从开始重置。我有自定义进度可绘制,setProgress 根本没有帮助我。所以我所做的是在实际设置之前调用此方法真正的可绘制setProgressDrawable(null)这是一种肮脏的方式清除,但它会做你想做的事,然后用你自己的progressdrawable调用相同的方法,所以感觉它已经被刷新了。就是这样......不幸的是,没有其他方法可以实现这一点.

    【讨论】:

      【解决方案2】:

      实际上 setProgress(0) 只有在进度启动时才会刷新显示。 因此,您可以通过在 setProgress 之前调用 onStart 来强制刷新,如下所示:

      @Override
      protected void onPrepareDialog(int id, Dialog dialog) {
          super.onPrepareDialog(id, dialog);
          ProgressDialog progress = (ProgressDialog)dialog;
          progress.onStart();
          progress.setProgress(0);
      }
      

      【讨论】:

        【解决方案3】:

        这样使用ProgressDialog是不可能的。您的AsyncTask 应该每次都创建一个新实例。

        【讨论】:

        • 那么 Android 为什么还要处理回调和缓存呢?它仅适用于不确定的 ProgressDialogs 吗? Android 开发指南与我所做的几乎相同developer.android.com/guide/topics/ui/…
        • @volker238 我不明白你的评论。回调是在不阻塞UI线程的情况下更新进度对话框。
        • 回调(onCreateDialogonPrepareDialog)对 AlertDialogs 很有效。但是我遇到ProgressDialogs 不能以这种方式工作 - 至少我无法重用ProgressDialog 的实例,特别是不确定的进度微调器在我显示相同实例的秒数时没有动画。所以我总是在AsyncTask.onPreExecute() 中创建一个ProgressDialog 的新实例,并在AsyncTask.onPostExecute() 中将其关闭。这种方式效果很好。
        • @BDFun 我说的是 onCreateDialog 和 onPrepareDialog 回调,而不是 AsyncTask 中的回调。
        • @Arhimed 好的,那我想我会用 removeDialog 替换dismissDialog 并摆脱onPrepareDialog 回调,因为它没用。
        猜你喜欢
        • 1970-01-01
        • 2020-11-22
        • 2018-11-30
        • 1970-01-01
        • 1970-01-01
        • 2011-01-09
        • 1970-01-01
        相关资源
        最近更新 更多