关于开源项目android--Imagedownloader的学习笔记
2014-02-12 13:37
363 查看
一个开源项目,关于图像异步缓存下载的简单apps,网上有相应的代码,但是没有任何说明和讲解(英文blog中有,讲了一下框架),那就自己研究吧。
主要对ImageDownloader分析:
Bitmap downloadBitmap(String url);//从网站下载一幅图片,比较简单
HttpClient:
AndroidHttpClient:Apache DefaultHttpClient的子类,已经配置好默认的合理设置和Android注册过的方案。不能直接创建对象。
AndroidHttpClient newInstance(String userAgent,Context context)创建一个新HttpClient对象。
HttpResponse:一个HTTP应答。
HttpEntity getEntity(),获得应答的消息实例
HttpEntity:一个可以发送接收HTTP消息的实例。
在一些情况下,javaDoc根据它们的内容来源把entity分三种:streamed,即内容来源是数据流,一般不可重复的;self-contained,内容来自内存也意味着和连接以及其他entities没有关系,一般可重复;wrapping,内容从另一个entity获得。
InputStream getContent():创建实例的一个新的InputStream对象
consumeContent():这个方法被调用意味着这个实例的内容不再被请求了,而该实例分配的所有资源都会被释放。
但是在 BitmapFactory.decodeStream 之前版本的bug可能会阻止代码进行慢连接,而newFlushedInputStream(inputStream)方法可以解决这个问题。
static class FlushedInputStream extends FilterInputStream;其中里面的skip函数是为了使在以后的读输入流时准确的跳过n个字节。
如果在ListAdapter的getView方法中直接下载图片,效果会很卡,因为每一个新图像的显示都要等图像下载下来。
非常遗憾的是,AndroidHttpClient竟然不能在主线程里运行,否则会显示"This thread forbids HTTP requests" 错误信息。对于AsyncTask类,它提供其中一个最简单的方法来使新任务脱离UI线程运行。
我们创建了一个ImageDownloader类来负责生成这些新的下载任务(task),它提供download方法来分配一张从URL下载的图片到对应的ImageView中。
BitmapDownloaderTask是AsyncTask的子类,用来实际下载图片的。调用execute(url)来运行它,能够立即返回结果,这也是UI线程调用它的主要原因。
其中doInBackground方法中调用了downloadBitmap来下载图片,onPostExecute是当下载结束时UI线程调用的,将存储在BitmapDownloaderTask中的imageView和下载的Bitmap相关联,而这个ImageView是一个弱引用,可以被系统回收,所以要在onpostExecute中检查弱引用和这个imageView不为空。
对于ListView上的图像浏览,当用户快速滑动ListView时,某一个ImageView对象会被用到很多次,每一次显示都会触发一个下载,然后改变对应的图片。和大多数并行应用一样,有顺序相关的问题。在这个程序中,不能保证下载会按开始的顺序结束,有可能先开始的后下载完,,“ The result is that the image finally displayed in the list may come from a previous item, which simply happened to have
taken longer to download. ” 结果就是,由于与该item对应的网络图片下载慢,导致该item位置还暂时显示着之前的item显示的图片(还没被刷新,有可能长时间不被刷新)为了解决这个问题,我们应该记住下载的顺序,使得最后的下载会被有效地显示,要让每一个ImageView记住它们的上一次下载任务。因此我们给出了DownloadedDrawable类,向ImageView中加入对对应下载任务的弱引用来暂时绑定正在下载图片的ImageView。
static class DownloadedDrawable extends ColorDrawable ;//该类包含了一个对下载的弱引用
上面ImageDownload中的download修改为:
private static BitmapDownloaderTask getBitmapDownloaderTask(ImageView imageview);
//通过ImageView得到对应的下载
下面总结下载过程:
download(url , imageview)——>
@创建一个和该imageview相对应的下载任务,这个任务对imageview进行弱引用
@创建与这个任务相对应的DownloadedDrawable,对这个任务弱引用
@imageview加载DownloadedDrawable
@执行下载任务,下载对应url的图像 ——execute(url)进入下载任务类
在下载任务类中:
——>doInBackground ===>downloadBitmap(url) 下载图片,结果Bitmap作为下面的参数
——>onPostExcute(Bitmap)
@获得任务引用的imageview
@通过DownloadedDrawable获得该imageview所对应的任务
@如果当前任务是这个imageview所对应的任务,则设置这个imageview的图片为下载下来的Bitmap
imageview和任务相互弱引用,形成绑定关系
主要对ImageDownloader分析:
Bitmap downloadBitmap(String url);//从网站下载一幅图片,比较简单
HttpClient:
AndroidHttpClient:Apache DefaultHttpClient的子类,已经配置好默认的合理设置和Android注册过的方案。不能直接创建对象。
AndroidHttpClient newInstance(String userAgent,Context context)创建一个新HttpClient对象。
HttpResponse:一个HTTP应答。
HttpEntity getEntity(),获得应答的消息实例
HttpEntity:一个可以发送接收HTTP消息的实例。
在一些情况下,javaDoc根据它们的内容来源把entity分三种:streamed,即内容来源是数据流,一般不可重复的;self-contained,内容来自内存也意味着和连接以及其他entities没有关系,一般可重复;wrapping,内容从另一个entity获得。
InputStream getContent():创建实例的一个新的InputStream对象
consumeContent():这个方法被调用意味着这个实例的内容不再被请求了,而该实例分配的所有资源都会被释放。
但是在 BitmapFactory.decodeStream 之前版本的bug可能会阻止代码进行慢连接,而newFlushedInputStream(inputStream)方法可以解决这个问题。
static class FlushedInputStream extends FilterInputStream;其中里面的skip函数是为了使在以后的读输入流时准确的跳过n个字节。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | static class FlushedInputStream extends FilterInputStream { public FlushedInputStream(InputStream inputStream) { super(inputStream); } @Override public long skip(long n) throws IOException { long totalBytesSkipped = 0L; while (totalBytesSkipped < n) { long bytesSkipped = in.skip(n - totalBytesSkipped); if (bytesSkipped == 0L) { int byte = read();//read()只读一个字节,但返回0~255的随机数 if (byte < 0) { break; //到文件结尾 } else { bytesSkipped = 1; // 读一个字节,这里当跳过0个字节时为什么要读一个字节不是太懂…… } } totalBytesSkipped += bytesSkipped; } return totalBytesSkipped; } } |
非常遗憾的是,AndroidHttpClient竟然不能在主线程里运行,否则会显示"This thread forbids HTTP requests" 错误信息。对于AsyncTask类,它提供其中一个最简单的方法来使新任务脱离UI线程运行。
我们创建了一个ImageDownloader类来负责生成这些新的下载任务(task),它提供download方法来分配一张从URL下载的图片到对应的ImageView中。
1 2 3 4 5 6 | public class ImageDownloader { public void download(String url, ImageView imageView) { BitmapDownloaderTask task = new BitmapDownloaderTask(imageView); task.execute(url); } } |
其中doInBackground方法中调用了downloadBitmap来下载图片,onPostExecute是当下载结束时UI线程调用的,将存储在BitmapDownloaderTask中的imageView和下载的Bitmap相关联,而这个ImageView是一个弱引用,可以被系统回收,所以要在onpostExecute中检查弱引用和这个imageView不为空。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> { private String url; private final WeakReference<ImageView> imageViewReference; public BitmapDownloaderTask(ImageView imageView) { imageViewReference = new WeakReference<ImageView>(imageView); } @Override // Actual download method, run in the task thread protected Bitmap doInBackground(String... params) { // params comes from the execute() call: params[0] is the url. return downloadBitmap(params[0]); } @Override // Once the image is downloaded, associates it to the imageView protected void onPostExecute(Bitmap bitmap) { if (isCancelled()) { bitmap = null; } if (imageViewReference != null) { ImageView imageView = imageViewReference.get(); if (imageView != null) { BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView); // Change bitmap only if this process is still associated with this ImageView if (this == bitmapDownloaderTask) { imageView.setImageBitmap(bitmap); } } } } } |
taken longer to download. ” 结果就是,由于与该item对应的网络图片下载慢,导致该item位置还暂时显示着之前的item显示的图片(还没被刷新,有可能长时间不被刷新)为了解决这个问题,我们应该记住下载的顺序,使得最后的下载会被有效地显示,要让每一个ImageView记住它们的上一次下载任务。因此我们给出了DownloadedDrawable类,向ImageView中加入对对应下载任务的弱引用来暂时绑定正在下载图片的ImageView。
static class DownloadedDrawable extends ColorDrawable ;//该类包含了一个对下载的弱引用
1 2 3 4 5 6 | static class DownloadedDrawable extends ColorDrawable { private final WeakReference<BitmapDownloaderTask> bitmapDownloaderTaskReference; public DownloadedDrawable(BitmapDownloaderTask bitmapDownloaderTask) { super(Color.BLACK); bitmapDownloaderTaskReference = new WeakReference<BitmapDownloaderTask>(bitmapDownloaderTask); } public BitmapDownloaderTask getBitmapDownloaderTask() { return bitmapDownloaderTaskReference.get(); } } |
1 2 3 4 5 6 | public void download(String url, ImageView imageView) { if (cancelPotentialDownload(url, imageView)) { BitmapDownloaderTask task = new BitmapDownloaderTask(imageView); DownloadedDrawable downloadedDrawable = new DownloadedDrawable(task); imageView.setImageDrawable(downloadedDrawable); task.execute(url); } } |
//通过ImageView得到对应的下载
1 2 3 4 5 6 | private static BitmapDownloaderTask getBitmapDownloaderTask(ImageView imageView) { if (imageView != null) { Drawable drawable = imageView.getDrawable(); if (drawable instanceof DownloadedDrawable) { DownloadedDrawable downloadedDrawable = (DownloadedDrawable)drawable; return downloadedDrawable.getBitmapDownloaderTask(); } } return null; } |
download(url , imageview)——>
@创建一个和该imageview相对应的下载任务,这个任务对imageview进行弱引用
@创建与这个任务相对应的DownloadedDrawable,对这个任务弱引用
@imageview加载DownloadedDrawable
@执行下载任务,下载对应url的图像 ——execute(url)进入下载任务类
在下载任务类中:
——>doInBackground ===>downloadBitmap(url) 下载图片,结果Bitmap作为下面的参数
——>onPostExcute(Bitmap)
@获得任务引用的imageview
@通过DownloadedDrawable获得该imageview所对应的任务
@如果当前任务是这个imageview所对应的任务,则设置这个imageview的图片为下载下来的Bitmap
imageview和任务相互弱引用,形成绑定关系
相关文章推荐
- 关于开源项目android--Imagedownloader的学习笔记
- 关于开源项目android--Imagedownloader的学习笔记
- 关于开源项目android--Imagedownloader的学习笔记
- 关于开源项目android--Imagedownloader的学习笔记
- Android开源项目SlidingMenu的学习笔记(一)
- Android开源项目SlidingMenu的学习笔记(二)
- Android开源项目学习笔记(一)--ActionBarSherlock
- Android笔记:2017年比较适合学习的开源项目
- 关于 Android 开源项目汇总、学习、源码解析
- Android 开源项目-StandupTimer学习笔记索引
- Android(java)学习笔记207:开源项目使用之gif view
- Android开源项目学习笔记(二)--SlidingMenu
- 关于 Android 开源项目汇总、学习、源码解析
- Android开源项目学习笔记_ActionBarSherlock
- 【学习笔记】关于Android的Surface系统
- 开源项目Meizhi学习笔记--RatioImageView
- Android开发者应该深入学习的10个开源应用项目
- Android 开源项目及其学习
- 开发者应深入学习的10个Android开源应用项目
- Android(java)学习笔记188:关于构造代码块,构造函数的一道面试题(华为面试题)