ImgageLoader学习总结

来源:互联网 发布:特种兵选吧 知乎 编辑:程序博客网 时间:2024/06/07 18:25

主要功能:
图片的同步加载
图片的异步加载
图片压缩
内存缓存
磁盘缓存
网络拉取

一、图片的同步加载
loadBitmap(String uri, intreqWidth, intreqHeight)
1、如果内存中已经存在,从内存中加载,bitmap = loadBitmapFromMemCache(uri)
2、如果磁盘中已经存在,从磁盘中加载,bitmap = loadBitmapFromDiskCache(uri,reqWidth,reqHeight),这个方法会先从磁盘中取出原图,然后对图片进行压缩,将压缩后的图片返回并存放在内存中
3、如果内存、磁盘中都不存在,要从网络中加载bitmap = loadBitmapFromHttp(uri,reqWidth,reqHeight)
在网络中加载到图片之后,该方法先图片存入磁盘中downloadUrlToStream(url,outputStream)(此时存储的是原图,不对图片进行压缩)
然后根据url再从磁盘中取出对应的图片loadBitmapFromDiskCache(url,reqWidth,reqHeight),这个方法首先会对图片进行压缩,将压缩后的图片返回并通过addBitmapToMemoryCache(key,bitmap)存放在内存中
4、如果磁盘缓存没有建立,则只从网络中拉取图片bitmap = downloadBitmapFromUrl(uri),不对图片进行缓存,也没对图片进行压缩,可能不太好
注意:网络访问不能在主线程中进行,所以在访问网络时要有是否在主线程中的判断
if(Looper.myLooper() == Looper.getMainLooper()) {
   throw newRuntimeException("can not visit network from UI Thread.");
}
二、图片的异步加载
bindBitmap(finalString uri, finalImageView imageView, final intreqWidth, final intreqHeight)
1、给imageView设置tag,imageView.setTag(TAG_KEY_URI,uri)
2、如果内存中存在,从内存中加载进imageView中
3、如果内存中不存在,在线程池中通过loadBitmap(uri,reqWidth,reqHeight)获取图片
4、通过线程池运行loadBitmapTask,THREAD_POOL_EXECUTOR.execute(loadBitmapTask)
5、通过Handler将消息发送至主线程mMainHandler.obtainMessage(MESSAGE_POST_RESULT,result).sendToTarget(),其中Handler的代码如下(handler由主线程的looper构造而成,所以handler中代码运行在主线程中):
privateHandlermMainHandler=newHandler(Looper.getMainLooper()) {
   @Override
   public voidhandleMessage(Message msg) {
        LoaderResult result = (LoaderResult) msg.obj;
       ImageView imageView = result.imageView;
       String uri = (String) imageView.getTag(TAG_KEY_URI);
        if(uri.equals(result.uri)) {
            imageView.setImageBitmap(result.bitmap);
       }else{
            Log.w(TAG,"set image bitmap,but url has changed, ignored!");
       }
    }
};
三、图片压缩
使用BitmapFactory将从磁盘或Resource位置的图片压缩后加载进内存中:
1、将BitmapFactor.Options的inJustDecodeBounds参数设置为true并加载图片(将inJustDecodeBounds设置为true时,BitmapFactory只会去解析图片的原始宽/高信息并不会真正地去加载图片到内存)
2、从BitmapFactory.Options中取出图片的原始宽高信息,他们对应于outWidth和outHeight参数
final intheight = options.outHeight;
final intwidth = options.outWidth;
3、根据采样率的规则(inSampleSize = 2^n)并结合目标View的所需大小(reqWidth、reqHeight)计算出采样率inSampleSize(小于reqWidth及reqHeight的最大outWidth、outHeight)
4、将BitmapFactory.Options的inJustDecodeBounds参数设为false,然后重新加载图片
bitmap = BitmapFactory.decodeFileDescriptor(fd, null, options)
代码片段:
// First decode with inJustDecodeBounds=true to check dimensions
finalBitmapFactory.Options options =newBitmapFactory.Options();
options.inJustDecodeBounds=true;
BitmapFactory.decodeFileDescriptor(fd, null, options);
// Calculate inSampleSize
options.inSampleSize= calculateInSampleSize(options,reqWidth,
       reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds=false;
returnBitmapFactory.decodeFileDescriptor(fd, null, options);

四、内存缓存
存入内存:
private voidaddBitmapToMemoryCache(String key,Bitmap bitmap) {
   if(getBitmapFromMemCache(key) ==null) {
       mMemoryCache.put(key,bitmap);
   }
}
从内存中获取:
privateBitmaploadBitmapFromMemCache(String url) {
   finalString key = hashKeyFormUrl(url);
   Bitmap bitmap = getBitmapFromMemCache(key);
    returnbitmap;
}


五、磁盘缓存
这是唯一一处将图片存入磁盘的操作,发生在图片从网络上取得之后,相比存入内存,存入磁盘的操作要复杂一些,包括editor =mDiskLruCache.edit(key) OutputStream outputStream = editor.newOutputStream(DISK_CACHE_INDEX) editor.commit();mDiskLruCache.flush()
代码如下:
privateBitmaploadBitmapFromHttp(String url, int reqWidth, intreqHeight)
       throwsIOException {
   if(Looper.myLooper() == Looper.getMainLooper()) {
       throw newRuntimeException("can not visit network from UI Thread.");
   }
   if(mDiskLruCache==null) {
       return null;
   }
   
    String key = hashKeyFormUrl(url);
   DiskLruCache.Editor editor =mDiskLruCache.edit(key);
    if(editor !=null) {
        OutputStream outputStream = editor.newOutputStream(DISK_CACHE_INDEX);
        if(downloadUrlToStream(url,outputStream)) {
            editor.commit();
       }else{
            editor.abort();
       }
       mDiskLruCache.flush();
   }
   returnloadBitmapFromDiskCache(url,reqWidth,reqHeight);
}

六、Adapter中view复用的错位问题
一个是要在handler中处理,当uri发生改变时,直接忽略,不对imageView进行设置:
public voidhandleMessage(Message msg) {
    LoaderResult result = (LoaderResult) msg.obj;
   ImageView imageView = result.imageView;
   String uri = (String) imageView.getTag(TAG_KEY_URI);
    if(uri.equals(result.uri)) {
        imageView.setImageBitmap(result.bitmap);
   }else{
        Log.w(TAG,"set image bitmap,but url has changed, ignored!");
   }
}
另外,在发生滑动的时候,预先设置一张默认图片将以前的图片覆盖掉:
publicViewgetView(intposition,View convertView,ViewGroup parent) {
    ViewHolder holder =null;
    if(convertView ==null) {
        convertView =mInflater.inflate(R.layout.image_list_item,parent, false);
       holder =newViewHolder();
       holder.imageView= (ImageView) convertView.findViewById(R.id.image);
       convertView.setTag(holder);
   }else{
        holder = (ViewHolder) convertView.getTag();
   }
    ImageView imageView = holder.imageView;
    finalString tag = (String)imageView.getTag();
    finalString uri = getItem(position);
    //是为了在滑动的时候,先设置一张默认图片将以前的图片覆盖掉
    if(!uri.equals(tag)) {
        imageView.setImageDrawable(mDefaultBitmapDrawable);
   }
   if(mIsGridViewIdle&&mCanGetBitmapFromNetWork) {
        imageView.setTag(uri);
       mImageLoader.bindBitmap(uri,imageView,mImageWidth,mImageWidth);
   }
   returnconvertView;
}

github代码地址:https://github.com/Gaoee/android-art-res/tree/master/Chapter_12
0 0
原创粉丝点击