异步下载后的Android RecyclerView持久图像

时间:2016-03-24 13:37:22

标签: android android-asynctask imageview android-recyclerview

一点背景......

我有一个使用MVP设计的应用程序,它将图像和文本显示为RecyclerView内的卡片。在打开应用程序时,会提取API信息,其中包括图像下载URL。在我<RecyclerView.ViewHolder> Adapter内。我执行AsyncTask下载每张卡片的图像,每张卡片创建时,每张图片下载(或卡片)都有自己的线程。在下载过程中,空灰色方块显示为占位符。所有这些都按预期工作,但......

问题是......

虽然所有这些都有效,但我注意到当我向上(或向下)向上滚动并创建新的卡片视图时,图像会再次下载。是否有可能在下载图像后,在重新创建相同的卡(或其索引)时不需要再次下载它们。这可以在 Play报亭 Instagram 应用程序或包含图像列表的任何应用程序中看到。

那么我怎样才能在我的应用程序中实现这一目标?

可能的解决方案......

I)使用RecyclerView在创建ThreadPoolExecutor之前和期间下载所有图片(而不仅仅是网址),并将其传递到我们的<RecyclerView.ViewHolder> Adapter

II)使用 ViewHolder 模式。当绑定我的适配器内部的ImageView时,它将引用presenter / model层中的一个对象,该对象将提供存储的图像,如果没有可用的图像,则下载一个。

III)在绑定之前添加某种逻辑,例如

if(image has already been download) {
    getDownloadedImage()
} else {
    downloadNewImage()
}

任何建议或推动正确的方向将不胜感激!

如果您需要更多信息或代码,请与我们联系。

代码......

NewsAdapter

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

    switch (holder.getItemViewType()) {
        case IMAGE_LAYOUT:
            ImageViewHolder imageViewHolder = (ImageViewHolder) holder;
            initViewholderImage(imageViewHolder, position);
            break;

        default:
            break;
    }

}

private void initViewholderImage(ImageViewHolder holder, int position) {
    holder.titleText.setText(articleList.get(position).getTitle());
    holder.abstractText.setText(articleList.get(position).getAbstract());
    holder.globalText.setText(articleList.get(position).getGeoFacet().get(0));

    try {
//this is where we are downloading our image in a background thread
     ImageDownload imageDownloader = new ImageDownloader();
        imageDownloader.imageDownload(articleList.get(position).getMultimedia().get(3).getUrl(),
                holder.articleImage);
    } catch(Exception e) {
        e.printStackTrace();
    }
}

ImageDownloader

public class ImageDownloader {
private final String TAG = getClass().getSimpleName();

public ImageDownloader() {

}

public void imageDownload(String url, ImageView imageView) {

    if(cancelPotentialDownload(url, imageView)) {
        BitmapDownloaderAsyncTask asyncTask = new BitmapDownloaderAsyncTask(imageView);
        DownloadDrawable downloadDrawable = new DownloadDrawable(asyncTask);
        imageView.setImageDrawable(downloadDrawable);
        asyncTask.execute(url);
    }
}

private static BitmapDownloaderAsyncTask getBitmapDownloaderTask(ImageView imageView) {
    if (imageView != null) {
        Drawable drawable = imageView.getDrawable();
        if (drawable instanceof DownloadDrawable) {
            DownloadDrawable downloadedDrawable = (DownloadDrawable)drawable;
            return downloadedDrawable.getBitmapDownloadTask();
        }
    }
    return null;
}

private static boolean cancelPotentialDownload(String url, ImageView imageView) {
    BitmapDownloaderAsyncTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);

    if (bitmapDownloaderTask != null) {
        String bitmapUrl = bitmapDownloaderTask.url;
        if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) {
            bitmapDownloaderTask.cancel(true);
        } else {
            // The same URL is already being downloaded.
            return false;
        }
    }
    return true;
}

class BitmapDownloaderAsyncTask extends AsyncTask<String, Void, Bitmap> {

    private String url;
    private final WeakReference<ImageView> weakImageView;

    public BitmapDownloaderAsyncTask(ImageView imageView) {
        weakImageView = new WeakReference<ImageView>(imageView);
    }

    @Override
    protected Bitmap doInBackground(String... params) {

        return ImageHelper.getBitmapFromURL(params[0]); //parameters are given in an array
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if (isCancelled()) {
            bitmap = null;
        }

        if (weakImageView != null) {
            ImageView imageView = weakImageView.get();
            if (imageView != null) {
                imageView.setImageBitmap(bitmap);

                /*int bgColor = Palette.from(bitmap).generate().getDarkVibrantColor(
                        ContextCompat.getColor(App.getAppComponent().getApplicationContext(), android.R.color.black));

                bgLayout.setBackgroundColor(bgColor);*/
            }
        }
    }
}

static class DownloadDrawable extends ColorDrawable { //can we change this to a Bitmap Drawable
    private final WeakReference<BitmapDownloaderAsyncTask> weakBitmapAsyncTask;

    public DownloadDrawable(BitmapDownloaderAsyncTask task) {
        super(Color.LTGRAY);
        weakBitmapAsyncTask = new WeakReference<BitmapDownloaderAsyncTask>(task);
    }

    public BitmapDownloaderAsyncTask getBitmapDownloadTask() {
        return weakBitmapAsyncTask.get();
    }
}

}

NewsActivity

public class NewsActivity extends BaseActivity implements NewsView{
private final String TAG = getClass().getSimpleName();

private static NewsPresenterComponent newsPresenterComponent;

@Inject NewsPresenter presenter;

RecyclerView recyclerView;
NewsAdapter adapter;

List<Article> articles;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_news);

    implementComponents();

    articles = presenter.queryNews("world", 20);

    initializeRecyclerView();

}

public void implementComponents() {
    newsPresenterComponent = DaggerNewsPresenterComponent.builder()
            .newsPresenterModule(new NewsPresenterModule(this, this)) //this can be removed
            .build();
    newsPresenterComponent.inject(this);
}

private void initializeRecyclerView() {
    recyclerView = (RecyclerView) findViewById(R.id.list);
    final LinearLayoutManager layoutManager = new LinearLayoutManager(this);
    layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
    recyclerView.setLayoutManager(layoutManager);

    adapter = new NewsAdapter(this, articles);
    recyclerView.setAdapter(adapter);
}

@Override
public void updateNewsAdapter() {
    adapter.notifyDataSetChanged();
}

}

1 个答案:

答案 0 :(得分:0)

只需使用具有内置缓存,占位符图片和许多其他内容的Picasso。您可以只用一行替换整个ImageDownloader类。