ImgageLoader学习总结


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

一、图片的同步加载
loadBitmap (String uri , int reqWidth , int reqHeight)
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 new RuntimeException( "can not visit network from UI Thread." ) ;
}
二、图片的异步加载
bindBitmap ( final String uri , final ImageView imageView , final int reqWidth , final int reqHeight)
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中代码运行在主线程中):
private Handler mMainHandler = new Handler(Looper. getMainLooper ()) {
    @Override
    public void handleMessage (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 int height = options. outHeight ;
final int width = 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
final BitmapFactory.Options options = new BitmapFactory.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;
return BitmapFactory. decodeFileDescriptor (fd , null, options) ;

四、内存缓存
存入内存:
private void addBitmapToMemoryCache (String key , Bitmap bitmap) {
    if (getBitmapFromMemCache(key) == null ) {
        mMemoryCache .put(key , bitmap) ;
    }
}
从内存中获取:
private Bitmap loadBitmapFromMemCache (String url) {
    final String key = hashKeyFormUrl(url) ;
    Bitmap bitmap = getBitmapFromMemCache(key) ;
    return bitmap ;
}


五、磁盘缓存
这是唯一一处将图片存入磁盘的操作,发生在图片从网络上取得之后,相比存入内存,存入磁盘的操作要复杂一些,包括 editor = mDiskLruCache .edit(key) OutputStream outputStream = editor.newOutputStream( DISK_CACHE_INDEX ) editor.commit() ;mDiskLruCache .flush()
代码如下:
private Bitmap loadBitmapFromHttp (String url , int reqWidth , int reqHeight)
        throws IOException {
    if (Looper. myLooper () == Looper. getMainLooper ()) {
        throw new RuntimeException( "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() ;
    }
    return loadBitmapFromDiskCache(url , reqWidth , reqHeight) ;
}

六、Adapter中view复用的错位问题
一个是要在handler中处理,当uri发生改变时,直接忽略,不对imageView进行设置:
public void handleMessage (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!" ) ;
    }
}
另外,在发生滑动的时候,预先设置一张默认图片将以前的图片覆盖掉:
public View getView ( int position , View convertView , ViewGroup parent) {
    ViewHolder holder = null;
    if (convertView == null ) {
        convertView = mInflater .inflate(R.layout. image_list_item , parent , false ) ;
        holder = new ViewHolder() ;
        holder. imageView = (ImageView) convertView.findViewById(R.id. image ) ;
        convertView.setTag(holder) ;
    } else {
        holder = (ViewHolder) convertView.getTag() ;
    }
    ImageView imageView = holder. imageView ;
    final String tag = (String)imageView.getTag() ;
    final String uri = getItem(position) ;
    //是为了在滑动的时候,先设置一张默认图片将以前的图片覆盖掉
    if (!uri.equals(tag)) {
        imageView.setImageDrawable( mDefaultBitmapDrawable ) ;
    }
    if ( mIsGridViewIdle && mCanGetBitmapFromNetWork ) {
        imageView.setTag(uri) ;
        mImageLoader .bindBitmap(uri , imageView , mImageWidth , mImageWidth ) ;
    }
    return convertView ;
}

github代码地址:https://github.com/Gaoee/android-art-res/tree/master/Chapter_12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值