public class BitmapLoader {
MainActivity context;
LruCache<String, Bitmap> lruCache;
private File cacheDir ;
public static final Executor THEAD_POOL_EXECUTOR= Executors.newFixedThreadPool(3);
public BitmapLoader(MainActivity context) {
this.context=context;
cacheDir = context.getCacheDir(); //!!!本地文件路径获取!!
int maxSize = (int) (Runtime.getRuntime().freeMemory() /2);
lruCache = new LruCache<String, Bitmap>(maxSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
// TODO Auto-generated method stub
return value.getRowBytes() * value.getHeight();
}
};
//存储缓存
}
//
private Bitmap loadBitmap(String url) {
//从内存获取
Bitmap bitmap =loadFromMemCache(url);
if(bitmap!=null){
Log.d("加载","从内存中获取");
return bitmap;
}
//从存储内存中获取
bitmap=loadFromFileCache(url);
if(bitmap!=null){
Log.d("加载","从文件中获取");
return bitmap;
}
else {
//从网络获取
bitmap=downLoadFromNet(url);
Log.d("加载","从网络中获取");
return bitmap;
}
}
//显示 开启一个线程池 先得到图片,然后在主线程,将图片绑定
public void displayBitmap(final String url, final ImageView imageView){
Runnable loadBitmapTask=new Runnable() {
@Override
public void run() {
final Bitmap bitmap=loadBitmap(url);
if(bitmap!=null){
//获取到主线程 重新在主线程中调用该方法!!这里是这样处理线程不能改变界面的问题的!
context.runOnUiThread(new Runnable() {
@Override
public void run() {
imageView.setImageBitmap(bitmap);
}
});
}
}
};
//在线程池中加载图片
THEAD_POOL_EXECUTOR.execute(loadBitmapTask);
}
//加密
public void putToMemCache(String url,Bitmap bitmap){
//把Url做Md5加密处理
lruCache.put(url,bitmap);
}
//不带算法的文件存储方式
public void saveBitmapToCacheFile(Bitmap bitmap,String ivUrl) {
File file = new File(cacheDir,Md5Utils.md5(ivUrl));
try {
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, new FileOutputStream(file));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/***
* 从内存中获取
* @param key
* @return
*/
public Bitmap loadFromMemCache(String key){
//将url进行解密处理,然后获取
Bitmap bitmap = lruCache.get(key);
if(bitmap!=null){
Log.d("获取非数据","11");
}
Log.d("获取空数据","11"+key);
return bitmap;
}
* @param ivUrl
* 当做缓存图片的名字
* @return
* 从文件中获取
*/
public Bitmap loadFromFileCache(String ivUrl){
//把ivUrl转换MD5值,再把md5 做文件名
File file = new File(cacheDir,Md5Utils.md5(ivUrl));
if (file != null && file.exists()) {
//文件存在
//把文件转换成bitmap
Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
if(bitmap!=null){
Log.d("写入","写入成功"+ivUrl);
putToMemCache(ivUrl, bitmap);
}else{
Log.d("写入","写入空数据");
}
//再往内存写
return bitmap;
} else {
return null;
}
}
/**
*
* @param bPurl
* @return
* 从网络中获取
*/
public Bitmap downLoadFromNet(final String bPurl) {
//开启线程! 获取Bitmap
//这里可以用线程池处理?
Bitmap bitmap=null;
HttpURLConnection connection = null;
try {
URL url1 = new URL(bPurl);
connection = (HttpURLConnection) url1.openConnection();
connection.setReadTimeout(8000);
connection.setRequestMethod("GET");
InputStream inputStrearms = connection.getInputStream();
bitmap = BitmapFactory.decodeStream(inputStrearms);
//本地存储
saveBitmapToCacheFile(bitmap,bPurl);
putToMemCache(bPurl,bitmap);
} catch (ProtocolException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
finally {
if(connection!=null){
connection.disconnect();
}
}
return bitmap;
}
}
缓存思想:
先内存,没有本地,内有网络
并在获取后向下添加数据,以求减少流量损耗!
而缓存的思想是当 所用容器满时 则自动删除旧的数据,存入新的数据从而达到缓存的目的
LruCache 就是 这种算法的容器。支持泛型什么的。。。。。。
如何异步处理时通过子线程更新UI的?
2.通过线程池 和Handler进行处理!(需要判断当前运行该方法的线程是否为主线程如果是则不可以)
这里进行了简化处理直接获取到主Activity 并runOnUIThread();
3.为什么采用线程池处理而不采用线程?: 因为在列表下滑是可能产生大量的线程!!
AsyncTask 为什么不适用? 因为无法实现并发效果!
线程池的使用方式:
如上方式4.复用错位问题处理?
由于多线程 和 复用问题 所以可能会出现由于 线程过慢加载引发的图片错位问题
解决方式:保存URL并判断是否为最新的URL
采用HashMap作为存储容器,当KEY相同值不同时 再次赋值,此时的Value将会被覆盖。
//保留最后一次访问url的信息
private Map<ImageView,String> urlImageViewDatas = new HashMap<ImageView, String>();
从网络获取后,将URL保留。
// 3. 从网络取
urlImageViewDatas.put(iv, ivUrl);//保留最后一次访问的url
当缓存的内容线程加载过慢而,本该显示新的URL内容的view给覆盖了,因这个被复用的view本应该显示新的URL的内容。‘
所以当缓存的view加载图片是要先判断,URL是否发生了改变,如果发生改变 ,就该设置最新的URL的内容。
在设置前判断是否是最新的URL
// 显示图片
// 判断url是不是最新的
//是最新的 自己的数据
if (ivUrl.equals(urlImageViewDatas.get(iv))) {
//自己的数据
iv.setImageBitmap(bitmap);
}
解决图片错位的整体代码:
public void displayBitmap(final String url, final ImageView imageView){
Runnable loadBitmapTask=new Runnable() {
@Override
public void run() {
final Bitmap bitmap=loadBitmap(url);
//在此处将URL记录下来
// 3. 从网络取
urlImageViewDatas.put(bitmap,url);//保留最后一次访问的url
if(bitmap!=null){
//获取到主线程 重新在主线程中调用该方法!!这里是这样处理线程不能改变界面的问题的!
context.runOnUiThread(new Runnable() {
@Override
public void run() {
//在这之前监测URL是否发生了改变?
if (url.equals(urlImageViewDatas.get(url))) {
//自己的数据
imageView.setImageBitmap(bitmap);
}
}
});
}
}
};
5.没有采用存储缓存 因为不是SDK里的内容 且 更加复杂,用editer 的方法进行写入和读出, 同样是用LRU算法
6.在添加缓存前可对图片进行压缩,听过Options参数 进行采样缩放 !通过裁剪 减少出现内存溢出的问题!
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
上面的一切没看懂不要紧。
框架开始了!!!
Universal Image Loader 框架! jar包 gihub上有
1.apllacation 配置:
ImageLoaderConfiguration configuration = ImageLoaderConfiguration
.createDefault(this);
//Initialize ImageLoader with configuration.
ImageLoader.getInstance().init(configuration);
2.缓存的参数配置:
DisplayImageOptions options = new DisplayImageOptions.Builder()
.resetViewBeforeLoading(false) // default
.delayBeforeLoading(1000)
.cacheInMemory(false) // default
.cacheOnDisk(false) // default
.considerExifParams(false) // default
.imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default
.bitmapConfig(Bitmap.Config.ARGB_8888) // default
.displayer(new SimpleBitmapDisplayer()) // default
.handler(new Handler()) // default
.build();
ImageSize mImageSize = new ImageSize(100, 100);
//显示图片的配置
DisplayImageOptions optionss = new DisplayImageOptions.Builder()
.cacheInMemory(true)
.cacheOnDisk(true)
.bitmapConfig(Bitmap.Config.RGB_565)
.build();
3.绑定并完成简单的监听过程,包括图片加前后的默认图片等等:
ImageLoader.getInstance().loadImage(newsListData.get(position).getListimage(),mImageSize, optionss, new SimpleImageLoadingListener(){
@Override
public void onLoadingComplete(String imageUri, View view,
Bitmap loadedImage) {
super.onLoadingComplete(imageUri, view, loadedImage);
finalHolder.iv_newspic.setImageBitmap(loadedImage);
}
});
return convertView;
}
用这个框架的好处是,避免了OOM和,并处理了缓存,同时,可以进行大小缩放 图片旋转的各种功能!!!!!
同类框架:picasso!!
----------------------------------------
Bitmap 转换时 可以通过BitmapFactory 进行缩放和设定(减少图片所占的内存)
Android中BitmapFactory.Options
(1 / inSampleSize) 2的幂函数 等其他
详细参数配置地址:
http://blog.csdn.net/haozipi/article/details/47183543?ref=myread