学习谷歌文档,总结如下:
1.图片加载框架的封装
1)利用HttpURLConnection来封装网络加载图片的方法
2)创建自定义的AsyncTask来封装1)中加载网络图片的方法,并显示到控件上。
3)暴露方法封装2)中自定义的加载并显示图片的AsyncTask
走完上面这几步,只需调用一个方法,就可以从网络上加载一张图片并且显示到控件上了。
解决List并发下载图片错位的问题
但是,谷歌文档中说上面代码会存在一个问题。就是如果在List里使用,复用的话,可能会发生图
图片错位的问题:就是某个item显示的图片,可能显示的图片是之前的item的图片。因为之前的这
张图片可能加载时间比较长,滑动后imageview是复用的,所以后面的item可能会显示之前的item的
图片。
这种就是由于并发产生的问题,谷歌工程师是这么解决问题的:
1》定义一个类 class DownloadedDrawable extends ColorDrawable,然后将下载的异步任务
DownloadAsyncTask与其绑定起来。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public
static
void
display(Context context,String url, ImageView imageView) {
Bitmap bitmapFromMemCache = LruCacheUtil.getBitmapFromMemCache(url);
if
(bitmapFromMemCache !=
null
){
imageView.setImageBitmap(bitmapFromMemCache);
}
else
{
if
(cancelPotentialDownload(url, imageView)) {
BitmapDownloaderTask task =
new
BitmapDownloaderTask(context,imageView);
DownloadedDrawable downloadedDrawable =
new
DownloadedDrawable(task);
imageView.setImageDrawable(downloadedDrawable);
task.execute(url);
}
}
}
|
2》定义2个方法
BitmapDownloaderTask getBitmapDownloaderTask(ImageView imageView)
--得到与ImageView绑定的异步下载任务
1
2
3
4
5
6
7
8
9
10
|
public
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
;
}
|
boolean cancelPotentialDownload(String url, ImageView imageView)
--取消可能正在进行的下载,并返回是否已经取消。
如果与imageView绑定的下载任务不为空,再判断与ImageView绑定的异步下载任务的URL,如果
为null或者是与当前方法传递进来URL不一致,说明异步下载任务正在执行之前的下载,就取消任
务,否则说明任务正在执行中且url一致,就不重新开启任务。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
private
static
boolean
cancelPotentialDownload(String url, ImageView imageView) {
BitmapDownloaderTask bitmapDownloaderTask = 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
;
}
|
解决图片缓存的问题
1》用内存来缓存,使用LruCache这个类。
内存的特点:
内存加载速度比较快,但是内存在开关机之后会被回收,缓存的数据会消失。
底层:
LinkedHashMap来实现存储
实现原理:
当从url下载图片之前,先判断缓存中存不存在图片,如果存在直接加载图片,不存在则
去网络请求图片。
当AsyncTask下载完图片之后,如果不为null,就存放到缓存中。
于是我写了个工具类LruCacheUtils来完成图片的缓存
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
public
class
LruCacheUtil {
//LruCache for bitmap
private
static
LruCache<String, Bitmap> mMemoryCache;
static
{
// Get max available VM memory, exceeding this amount will throw an
// OutOfMemory exception. Stored in kilobytes as LruCache takes an
// int in its constructor.
final
int
maxMemory = (
int
) (Runtime.getRuntime().maxMemory() /
1024
);
// Use 1/8th of the available memory for this memory cache.
final
int
cacheSize = maxMemory /
8
;
mMemoryCache =
new
LruCache<String, Bitmap>(cacheSize) {
@TargetApi
(Build.VERSION_CODES.HONEYCOMB_MR1)
@Override
protected
int
sizeOf(String key, Bitmap bitmap) {
// The cache size will be measured in kilobytes rather than
// number of items.
return
bitmap.getByteCount() /
1024
;
}
};
}
public
static
void
addBitmapToMemoryCache(String key, Bitmap bitmap) {
if
(getBitmapFromMemCache(key) ==
null
) {
mMemoryCache.put(key, bitmap);
}
}
public
static
Bitmap getBitmapFromMemCache(String key) {
return
mMemoryCache.get(key);
}
}
|
2》使用磁盘(Disk)来缓存,使用DiskLruCache(这个类google文档里并没有提供)
Android DiskLruCache 源码解析 硬盘缓存的绝佳方案
http://blog.csdn.net/lmj623565791/article/details/47251585
下载链接
http://http://www.oschina.net/p/disklrucache
Android本地缓存DiskLruCache完整详细学习示例
http://www.2cto.com/kf/201501/368172.html
虽然利用内存来缓存,加载图片的时候速度比较快,但是像GridView会很快地占满内存。当应
用非正常关闭(如被电话应用打断、运行在后台的时候被杀死)会导致cache被销毁清空。
注意:获取图片应该在后台进行
Of course, fetching images from disk is slower than loading from memory and should be done in a
background thread, as disk read times can be unpredictable.(from google doc)
缓存位置:
有外部存储设备就存放到外部存储设备中,否则存放到应用包名目录下。
2.布局优化
sdk下的一些工具并不是专门针对Eclipse的,Android Studio也可以使用。
sdk/tools下的工具Hierarchy Viewer
http://wear.techbrood.com/training/improving-layouts/optimizing-layout.html#Inspect
爽处1:可以查看布局结构某个节点的3个方法Measure、Layout、Draw执行所需要的时间,这样
如果某个item的加载时间比较长,你就应该要优化了。
使用这个工具可能会遇到的问题:
问题:使用Hierarchyviewer,measure、layout、draw时间未显示?
解决办法:点击菜单 Profile Node,重新加载之后就有了
用Hierarchyviewer,measure、layout、draw时间未显示?
本文转自屠夫章哥 51CTO博客,原文链接:http://blog.51cto.com/4259297/1710561,如需转载请自行联系原作者