>我正在使用多个FragmentLists的应用程序
在自定义的FragmentStatePagerAdapter中.可能有,
可能有相当数量的此类碎片在20到40之间.
>每个片段都是一个列表,其中每个项目可以包含文本或图像.
>图像需要从Web异步上传并缓存到临时内存缓存,如果可用,还需要SD
>当片段离开屏幕时,任何上传和当前活动都应该被取消(不会暂停)
我的第一个实现遵循着名的image loader code来自谷歌.我对该代码的问题在于它基本上为每个图像创建了一个AsyncTask实例.在我的情况下,这快速杀死应用程序.
由于我使用的是v4兼容包,我认为使用扩展AsyncTaskLoader的自定义Loader会对我有所帮助,因为它内部实现了一个线程池.但令我不愉快的是,如果我执行此代码多次,每次调用后都会中断前一次.假设我在ListView#getView方法中有这个:
getSupportLoaderManager().restartLoader(0,args,listener);
对于进入视图的每个列表项,在循环中执行此方法.正如我所说 – 以下每次调用都将终止前一次调用.或者至少这是基于LogCat的事情
11-03 13:33:34.910: V/LoaderManager(14313): restartLoader in LoaderManager: args=Bundle[{URL=http://blah-blah/pm.png}] 11-03 13:33:34.920: V/LoaderManager(14313): Removing pending loader: LoaderInfo{405d44c0 #2147483647 : ImageLoader{405118a8}} 11-03 13:33:34.920: V/LoaderManager(14313): Destroying: LoaderInfo{405d44c0 #2147483647 : ImageLoader{405118a8}} 11-03 13:33:34.920: V/LoaderManager(14313): Enqueuing as new pending loader
然后我认为可能给每个加载器提供唯一的ID将有助于事情,但它似乎没有任何区别.结果我最终得到看似随机的图像,应用程序永远不会加载我需要的1/4.
问题
>什么是修复Loader做我想做的事情的方式(有没有方法?)
>如果不是什么是创建AsyncTask池的好方法,是否可能正在实施它?
为了让您了解这里的代码是剥离版本的Loader,其中实际的下载/保存逻辑位于单独的ImageManager类中.
public class ImageLoader extends AsyncTaskLoader<TaggedDrawable> { private static final String TAG = ImageLoader.class.getName(); /** Wrapper around BitmapDrawable that adds String field to id the drawable */ TaggedDrawable img; private final String url; private final File cacheDir; private final HttpClient client; /** * @param context */ public ImageLoader(final Context context,final String url,final File cacheDir,final HttpClient client) { super(context); this.url = url; this.cacheDir = cacheDir; this.client = client; } @Override public TaggedDrawable loadInBackground() { Bitmap b = null; // first attempt to load file from SD final File f = new File(this.cacheDir,ImageManager.getNameFromUrl(url)); if (f.exists()) { b = BitmapFactory.decodeFile(f.getPath()); } else { b = ImageManager.downloadBitmap(url,client); if (b != null) { ImageManager.saveToSD(url,cacheDir,b); } } return new TaggedDrawable(url,b); } @Override protected void onStartLoading() { if (this.img != null) { // If we currently have a result available,deliver it immediately. deliverResult(this.img); } else { forceLoad(); } } @Override public void deliverResult(final TaggedDrawable img) { this.img = img; if (isStarted()) { // If the Loader is currently started,we can immediately deliver its results. super.deliverResult(img); } } @Override protected void onStopLoading() { // Attempt to cancel the current load task if possible. cancelLoad(); } @Override protected void onReset() { super.onReset(); // Ensure the loader is stopped onStopLoading(); // At this point we can release the resources associated with 'apps' // if needed. if (this.img != null) { this.img = null; } } }
解决方法
如果您对AsyncTask加载程序性能不满意,则使用AsyncTaskLoader无法解决您的问题. AsyncTaskLoader只接受加载器接口并将其与AsyncTask结合.所以它实际上是映射onLoadFinished – > onPostExecute,onStart – > onLoadInBackground.所以它是完全相同的.
我们为我们的app使用相同的图像加载器代码,每次我们尝试加载图像时都会将asynctask放到线程池队列中.在谷歌的示例中,他们将imageview与其异步任务相关联,以便他们可以在尝试在某种适配器中重用imageview时取消异步任务.你应该在这里采取类似的策略.您应该将imageview与异步任务相关联,即在后台加载图像.当您有一个未显示的片段时,您可以循环浏览与该片段关联的图像视图并取消加载任务.简单地使用AsyncTask.cancel()应该可以正常工作.
您还应该尝试实现异步图像视图示例拼写出来的简单图像缓存机制.我们只需创建一个来自url – >的静态hashmap.弱引用.这样,图像可以在需要时被回收,因为它们仅用弱引用来保持.
这是我们所做的图像加载的概述
public class LazyLoadImageView extends ImageView { public WeakReference<ImageFetchTask> getTask() { return task; } public void setTask(ImageFetchTask task) { this.task = new WeakReference<ImageFetchTask>(task); } private WeakReference<ImageFetchTask> task; public void loadImage(String url,boolean useCache,Drawable loadingDrawable){ BitmapDrawable cachedDrawable = ThumbnailImageCache.getCachedImage(url); if(cachedDrawable != null){ setImageDrawable(cachedDrawable); cancelDownload(url); return; } setImageDrawable(loadingDrawable); if(url == null){ makeDownloadStop(); return; } if(cancelDownload(url)){ ImageFetchTask task = new ImageFetchTask(this,useCache); this.task = new WeakReference<ImageFetchTask>(task); task.setUrl(url); task.execute(); } ...... public boolean cancelDownload(String url){ if(task != null && task.get() != null){ ImageFetchTask fetchTask = task.get(); String downloadUrl = fetchTask.getUrl(); if((downloadUrl == null) || !downloadUrl.equals(url)){ fetchTask.cancel(true); return true; } else return false; } return true; } }
因此,只需旋转片段中的图像视图,然后在片段隐藏时取消它们,并在片段可见时显示它们.