我有大约1500张图片的网格视图。我正在使用MediaStore的缩略图来显示它们。但是当我在UI线程中填充网格时,它第一次工作得太慢了(缩略图还没有创建?)。所以我决定将这个过程转移到后台。使用这个tutorial和另一个我写了这个课:
public class ImageLoader {
// -----------------------------------------------------------------------
//
// Fields
//
// -----------------------------------------------------------------------
private static Context mContext;
private static ImageLoader mImageLoader = new ImageLoader();
// -----------------------------------------------------------------------
//
// Static methods
//
// -----------------------------------------------------------------------
public static void init(Application application){
mContext = application;
}
public static ImageLoader getInstance(){
return mImageLoader;
}
// -----------------------------------------------------------------------
//
// Methods
//
// -----------------------------------------------------------------------
public void download(ImageView imageView, final long id) {
Boolean b = cancelPotentialDownload(id, imageView);
Log.v("Loader", "download " + b.toString());
if (b) {
DownloadImageTask task = new DownloadImageTask(imageView, id);
DownloadedDrawable downloadedDrawable = new DownloadedDrawable(task);
imageView.setImageDrawable(downloadedDrawable);
task.execute();
}
}
// -----------------------------------------------------------------------
//
// Inner classes
//
// -----------------------------------------------------------------------
private class DownloadImageTask extends AsyncTask<Void, Void, Bitmap>{
private final WeakReference<ImageView> iv;
private final long id;
public DownloadImageTask(ImageView imageView, long id){
iv = new WeakReference<ImageView>(imageView);
this.id = id;
}
@Override
protected Bitmap doInBackground(Void... params) {
Bitmap bitmap = downloadImageThumbnail(id);
return bitmap;
}
@Override
protected void onPostExecute(Bitmap result) {
Log.v("Task", "completed " + (result == null));
if (iv != null) {
ImageView imageView = iv.get();
DownloadImageTask bitmapDownloaderTask = getDownloadImageTask(imageView);
// Change bitmap only if this process is still associated with it
if (this == bitmapDownloaderTask) {
imageView.setImageBitmap(result);
}
}
}
}
static class DownloadedDrawable extends ColorDrawable {
private final WeakReference<DownloadImageTask> downloadImageTaskReference;
public DownloadedDrawable(DownloadImageTask downloadImageTask) {
super(Color.TRANSPARENT);
downloadImageTaskReference = new WeakReference<DownloadImageTask>(downloadImageTask);
}
public DownloadImageTask getDownloadImageTask() {
return downloadImageTaskReference.get();
}
}
// -----------------------------------------------------------------------
//
// Private static helper methods
//
// -----------------------------------------------------------------------
private static boolean cancelPotentialDownload(long id, ImageView imageView) {
DownloadImageTask downloadImageTask = getDownloadImageTask(imageView);
if (downloadImageTask != null) {
long imageId = downloadImageTask.id;
if ((imageId == 0) || (imageId != id)) {
Boolean b = downloadImageTask.cancel(true);
Log.v("Task", "Stopped " + b.toString());
} else {
// The same URL is already being downloaded.
return false;
}
}
return true;
}
private static DownloadImageTask getDownloadImageTask(ImageView imageView) {
if (imageView != null) {
Drawable drawable = imageView.getDrawable();
if (drawable instanceof DownloadedDrawable) {
DownloadedDrawable downloadedDrawable = (DownloadedDrawable)drawable;
return downloadedDrawable.getDownloadImageTask();
}
}
return null;
}
// -----------------------------------------------------------------------
//
// Private helper methods
//
// -----------------------------------------------------------------------
private Bitmap downloadImageThumbnail(long id) {
Bitmap bitmap = MediaStore.Images.Thumbnails.getThumbnail(mContext.getContentResolver(), id, MediaStore.Images.Thumbnails.MICRO_KIND, null);
return bitmap;
}
}
但是有如此大量的图像存在问题 - 有很多任务同时运行,所以在活动开始后有一个空白的网格视图然后突然变得充满图像(我读过AsyncTask)来源,并不明白为什么它以这种方式工作 - 只有一个任务同时运行)。还有一个 - 如果你快速向下滚动图像的大型列表视图(1500),那么你需要等待太长时间才能看到结果。无论如何,我需要使gridview顺利填充。所以我决定自己管理任务并进行一些修改:
private static final int POOL_CAPACITY = 10;
// -----------------------------------------------------------------------
//
// Fields
//
// -----------------------------------------------------------------------
private static Context mContext;
private static ImageLoader mImageLoader = new ImageLoader();
private static ArrayList<DownloadImageTask> executingPool = new ArrayList<ImageLoader.DownloadImageTask>();
private static ArrayList<DownloadImageTask> waitingPool = new ArrayList<ImageLoader.DownloadImageTask>();
// -----------------------------------------------------------------------
//
// Static methods
//
// -----------------------------------------------------------------------
public static void init(Application application){
mContext = application;
}
public static ImageLoader getInstance(){
return mImageLoader;
}
// -----------------------------------------------------------------------
//
// Methods
//
// -----------------------------------------------------------------------
public void download(ImageView imageView, final long id) {
Boolean b = cancelPotentialDownload(id, imageView);
Log.v("Loader", "download " + b.toString());
if (b) {
DownloadImageTask task = new DownloadImageTask(imageView, id);
Log.v("Loader","download " + task.hashCode() + " ex size " + executingPool.size() + " wa size " + waitingPool.size());
DownloadedDrawable downloadedDrawable = new DownloadedDrawable(task);
imageView.setImageDrawable(downloadedDrawable);
addTask(task);
}
}
private void addTask(DownloadImageTask task){
Log.v("Loader", "addTask " + task.hashCode() + " ex size " + executingPool.size() + " wa size " + waitingPool.size());
if(executingPool.size() < POOL_CAPACITY) {
executingPool.add(task);
task.execute();
}
else
waitingPool.add(task);
}
private synchronized void executeNext(DownloadImageTask finished){
Log.v("Loader", "executeNext " + finished.hashCode() + " ex size " + executingPool.size() + " wa size " + waitingPool.size());
executingPool.remove(finished);
if(waitingPool.size() > 0){
DownloadImageTask task = waitingPool.remove(0);
addTask(task);
}
}
// -----------------------------------------------------------------------
//
// Inner classes
//
// -----------------------------------------------------------------------
private class DownloadImageTask extends AsyncTask<Void, Void, Bitmap>{
private final WeakReference<ImageView> iv;
private final long id;
public DownloadImageTask(ImageView imageView, long id){
iv = new WeakReference<ImageView>(imageView);
this.id = id;
}
@Override
protected Bitmap doInBackground(Void... params) {
Log.v("Loader", "doInBackground " + this.hashCode() + " ex size " + executingPool.size() + " wa size " + waitingPool.size());
Bitmap bitmap = downloadImageThumbnail(id);
return bitmap;
}
@Override
protected void onPostExecute(Bitmap result) {
Log.v("Task", "completed " + (result == null));
if (iv != null) {
ImageView imageView = iv.get();
DownloadImageTask bitmapDownloaderTask = getDownloadImageTask(imageView);
// Change bitmap only if this process is still associated with it
if (this == bitmapDownloaderTask) {
imageView.setImageBitmap(result);
}
}
executeNext(this);
}
}
static class DownloadedDrawable extends ColorDrawable {
private final WeakReference<DownloadImageTask> downloadImageTaskReference;
public DownloadedDrawable(DownloadImageTask downloadImageTask) {
super(Color.TRANSPARENT);
downloadImageTaskReference = new WeakReference<DownloadImageTask>(downloadImageTask);
}
public DownloadImageTask getDownloadImageTask() {
return downloadImageTaskReference.get();
}
}
// -----------------------------------------------------------------------
//
// Private static helper methods
//
// -----------------------------------------------------------------------
private static boolean cancelPotentialDownload(long id, ImageView imageView) {
DownloadImageTask downloadImageTask = getDownloadImageTask(imageView);
if (downloadImageTask != null) {
long imageId = downloadImageTask.id;
if ((imageId == 0) || (imageId != id)) {
Boolean b = downloadImageTask.cancel(true);
Log.v("Task", "Stopped " + b.toString());
} else {
// The same URL is already being downloaded.
return false;
}
}
return true;
}
private static DownloadImageTask getDownloadImageTask(ImageView imageView) {
if (imageView != null) {
Drawable drawable = imageView.getDrawable();
if (drawable instanceof DownloadedDrawable) {
DownloadedDrawable downloadedDrawable = (DownloadedDrawable)drawable;
return downloadedDrawable.getDownloadImageTask();
}
}
return null;
}
// -----------------------------------------------------------------------
//
// Private helper methods
//
// -----------------------------------------------------------------------
private Bitmap downloadImageThumbnail(long id) {
Bitmap bitmap = MediaStore.Images.Thumbnails.getThumbnail(mContext.getContentResolver(), id, MediaStore.Images.Thumbnails.MICRO_KIND, null);
return bitmap;
}
}
现在gridview填充速度更快,但仍然存在快速向下滚动的问题。而另一个 - 有时我得到一个错误:
java.lang.IllegalStateException: Cannot execute task: the task has already been executed (a task can be executed only once)
我真的不知道该怎么办。我试图使addTask和executeNext同步(我不擅长有关同步的问题),但它的工作甚至值得。我不知道任何第三方库有助于从媒体商店下载图片缩略图。也许你可以帮助我?