我需要在RecyclerView中显示一些图像。当用户滚动列表时,这些图像应该被呈现为“动态”。绘制每幅图像需要很长时间: 50-500ms。在图像显示给用户之前,会显示一个进度条。
由于渲染时间长,这个部分被放置在一个AsyncTask中。
见下面的代码:
class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
class ViewHolder extends RecyclerView.ViewHolder {
ImageView myImg;
ProgressBar myProgressBar;
public ViewHolder(View view) {
super(itemView);
myImg = view.findViewById(R.id.myImg);
myProgressBar = view.findViewById(R.id.myProgressBar);
}
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
holder.myProgressBar.setVisibility(View.VISIBLE);
AsyncTask.execute(() -> {
Bitmap bitmap = longRenderingFunction();
holder.myImg.post(() -> {
holder.myImg.setImageBitmap(bitmap);
holder.myProgressBar.setVisibility(View.GONE);如果用户正在缓慢滚动列表,例如每秒1-2个屏幕,则图像将被正确加载。有时人们会注意到进度条,它很快就消失了。
但是,如果用户滚动得非常快,图像就会出现,然后被替换,有时会被替换两次:

一般来说,在快速滚动时,很明显:
调用多个代码,并启动每个可回收项目的多个ImageView.。对于同一个项目,即使触发了一个新的onBindViewHolder,老的AsyncTask也会继续运行H 211H 112,然后AsyncTasks为相同的ViewHolder完成一个,在ImageView.>d17放置自己生成的位图后,将自己生成的位图放到ImageView.上。
我的意图是:
AsyncTasks
maximum:最低限度:不要从过时的setImageBitmap中尽快停止已经过时的AsyncTasks,以节省系统资源我很想听听这个问题的一些提示或可能的解决方案。
发布于 2020-09-01 19:43:08
这是我想出的解决办法。
停止闪烁
第一部分非常简单:
提出了一个简单的指数:
int loadingPosition;在onBindViewHolder开始时,保存当前位置:
holder.loadingPosition = position;在切换位图之前,将根据上次启动检查当前位置。如果一个新任务已经启动,索引已经更改,那么图像将不会被更新:
if (holder.loadingPosition == position) {
holder.myImg.setImageBitmap(bitmap);改善性能
为了防止任务在不需要时进一步运行,引入了一个Future对象。它允许管理已启动的任务,而AsyncTask不允许:
Future<?> future;通过ExecutorService而不是AsyncTask启动异步任务
holder.future = executor.submit(() -> { ...如果仍在运行任务,则停止正在运行的任务:
if ((holder.future != null) && (!holder.future.isDone()))
holder.future.cancel(true);完整代码
整个代码看起来是这样的:
class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private ExecutorService executor = Executors.newSingleThreadExecutor();
class ViewHolder extends RecyclerView.ViewHolder {
ImageView myImg;
ProgressBar myProgressBar;
int loadingPosition;
Future<?> future;
public ViewHolder(View view) {
super(itemView);
myImg = view.findViewById(R.id.myImg);
myProgressBar = view.findViewById(R.id.myProgressBar);
}
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
holder.loadingPosition = position;
if ((holder.future != null) && (!holder.future.isDone()))
holder.future.cancel(true);
holder.myProgressBar.setVisibility(View.VISIBLE);
holder.future = executor.submit(() -> {
Bitmap bitmap = longRenderingFunction();
holder.myImg.post(() -> {
if (holder.loadingPosition == position) {
holder.myImg.setImageBitmap(bitmap);
holder.myProgressBar.setVisibility(View.GONE);也许使用这两种方法有点过分,但它提供了某种程度的保险。
https://stackoverflow.com/questions/63441989
复制相似问题