一点背景......
我有一个使用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();
}
}