从 AsyncTask 滞后 UI 更新 ProgressBar
Posted
技术标签:
【中文标题】从 AsyncTask 滞后 UI 更新 ProgressBar【英文标题】:Updating ProgressBar from AsyncTask lagging UI 【发布时间】:2016-09-26 16:04:05 【问题描述】:我有一个Fragment
和一个RecyclerView
,而RecyclerView
的ViewHolder
持有一个ProgressBar
以显示下载过程的进度。
public static class ViewHolder extends RecyclerView.ViewHolder
....
private ProgressBar progressBar = null;
....
public ViewHolder(View itemView)
super(itemView);
....
this.progressBar = (ProgressBar) itemView.findViewById(R.id.progessbar);
....
我为我的Fragment
创建了一个回调:
public interface CallbackItemChanged
void onItemChanged(final int position);
如果它被调用,我会这样做:
@Override
public void onItemChanged(final int position)
this.adapter.notifyItemChanged(position);
在我的AsyncTask
:
protected void onProgressUpdate(Integer... progress)
super.onProgressUpdate(progress);
this.entry.setProgress(progress[0]);
this.entry.setProgressString(progress[0] + "%");
this.callbackItemChanged.onItemChanged(this.entry.getPosition());
进度已成功发布,但用户界面非常滞后,但我不知道为什么? onProgressUpdate
是在 ui 线程上运行的不是吗?我觉得应该是这样还是我错了?
如何在更新进度条时让 ui 顺利运行?
编辑
@Override
protected String doInBackground(Void... params)
this.inputStream = null;
this.outputStream = null;
this.connection = null;
File file = new File(this.entry.getPath(this.context));
File parent = file.getParentFile();
try
parent.mkdirs();
file.createNewFile();
this.connection = (HttpsURLConnection) new URL(this.entry.getUrl()).openConnection();
this.connection.connect();
int fileLength = this.connection.getContentLength();
this.inputStream = this.connection.getInputStream();
this.outputStream = new FileOutputStream(file);
byte data[] = new byte[4096];
long progress = 0;
int count;
while ((count = this.inputStream.read(data)) != -1)
if (this.isCancelled() || this.entry.isCancelled())
this.handleClose();
this.handleDelete();
return null;
if (fileLength > 0)
this.publishProgress((int) ((progress +=count) * 100 / fileLength));
this.outputStream.write(data, 0, count);
catch (Exception e)
this.handleDelete();
return e.toString();
finally
this.handleClose();
return null;
【问题讨论】:
请向我们展示您的整个 AsyncTask 代码。我们需要看看您是如何使用 publishProgress 方法发布进度的。 您可能会用进度更新淹没 UI,但如果没有任何代码表明您发布进度的时间和频率,我们对此无话可说。当您说“用户界面像地狱一样滞后”时,您的意思是用户界面在滚动时出现卡顿,或者可能是其他更量化的东西? 我添加了我的doInBackground
以显示我在哪里使用publishProgress
。是的,用户界面在滚动时卡顿。
【参考方案1】:
您在循环中发布进度,因此您的主线程将被调用很多次。
您可以使用简单的 Thread.sleep() 延迟发布进度:
while ((count = this.inputStream.read(data)) != -1)
if (this.isCancelled() || this.entry.isCancelled())
this.handleClose();
this.handleDelete();
return null;
// Write the data before publishing the progress
this.outputStream.write(data, 0, count);
try
// Adjust this value. It shouldn't be too small.
Thread.sleep(100);
catch (InterruptedException e)
// Nothing you can do here
finally
if (fileLength > 0)
this.publishProgress((int) ((progress +=count) * 100 / fileLength));
或者您只能以 x% 为增量发布:
while ((count = this.inputStream.read(data)) != -1)
if (this.isCancelled() || this.entry.isCancelled())
this.handleClose();
this.handleDelete();
return null;
// Write the data before publishing the progress
this.outputStream.write(data, 0, count);
if (fileLength > 0)
currentProgress = ((progress += count) * 100 / fileLength);
// Publish only on increments of 1%
if (currentProgress >= previousProgress + 1)
this.publishProgress(currentProgress);
previousProgress = currentProgress;
【讨论】:
这不会减慢下载过程吗? 是的。另一种方法是仅当您与之前的进度有一定差异时才发布。我会用一个例子来编辑我的答案。以上是关于从 AsyncTask 滞后 UI 更新 ProgressBar的主要内容,如果未能解决你的问题,请参考以下文章
从另一个 Activity 类执行 Fragment 中的 AsyncTask 并更新其中的 UI
如何从 Android AsyncTask 更改活动 UI?