volley中ImageLoader的理解和扩张
2015-11-13 19:48
489 查看
没有了解过Vollery的朋友,请自行google了解.这里不做复述.
先来看ImageLoader的关键源码:
public ImageContainer get(String requestUrl, ImageListener imageListener,
int maxWidth, int maxHeight) {
// only fulfill requests that were initiated from the main thread.
throwIfNotOnMainThread();
final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight);
// Try to look up the request in the cache of remote images.
Bitmap cachedBitmap = mCache.getBitmap(cacheKey);
if (cachedBitmap != null) {
// Return the cached bitmap.
ImageContainer container = new ImageContainer(cachedBitmap,
requestUrl, null, null);
imageListener.onResponse(container, true);
return container;
}
// The bitmap did not exist in the cache, fetch it!
ImageContainer imageContainer = new ImageContainer(null, requestUrl,
cacheKey, imageListener);
// Update the caller to let them know that they should use the default
// bitmap.
imageListener.onResponse(imageContainer, true);
// Check to see if a request is already in-flight.
BatchedImageRequest request = mInFlightRequests.get(cacheKey);
if (request != null) {
// If it is, add this request to the list of listeners.
request.addContainer(imageContainer);
return imageContainer;
}
// The request is not already in flight. Send the new request to the
// network and
// track it.
Request<Bitmap> newRequest = makeImageRequest(requestUrl, maxWidth,
maxHeight, cacheKey);
mRequestQueue.add(newRequest);
mInFlightRequests.put(cacheKey, new BatchedImageRequest(newRequest,
imageContainer));
return imageContainer;
}
这个是请求图片的接口,可以看到,他通过图片路径+高度+宽度生成了一个缓存的Key.然后会通过这个Key去mCache中查找是否有缓存图片.如果有的话,会直接直接把图片包装成一个ImageContainer.且直接返回,如果没有找找到的话.会生成一个一个请求,将这条请求入队.执行策略的话,内部是一个优先级的阻塞队列.而ImageRequest的优先级是low.在ImageRequest这个类的getPriority()接口会返回优先级.注意的是,onResponse接口的第二参数,表示是否是及时返回的.如果为true时,一般表示图片在内存中,所以一般如果参数为True的话,不用启动动画效果.为false的话表示进行了网络请求.这时即可对imageview进行一些动画的过度.
protected Request<Bitmap> makeImageRequest(String requestUrl, int maxWidth,
int maxHeight, final String cacheKey) {
return new ImageRequest(requestUrl, new Listener<Bitmap>() {
@Override
public void onResponse(Bitmap response) {
onGetImageSuccess(cacheKey, response);
}
}, maxWidth, maxHeight, Config.RGB_565, new ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
onGetImageError(cacheKey, error);
}
});
}
这个接口生产了一个ImageRequest对象.成功时会触发
protected void onGetImageSuccess(String cacheKey, Bitmap response) {
// cache the image that was fetched.
mCache.putBitmap(cacheKey, response);
// remove the request from the list of in-flight requests.
BatchedImageRequest request = mInFlightRequests.remove(cacheKey);
if (request != null) {
// Update the response bitmap.
request.mResponseBitmap = response;
// Send the batched response
batchResponse(cacheKey, request);
}
}
失败时会触发
protected void onGetImageError(String cacheKey, VolleyError error) {
// Notify the requesters that something failed via a null result.
// Remove this request from the list of in-flight requests.
BatchedImageRequest request = mInFlightRequests.remove(cacheKey);
if (request != null) {
// Set the error for this request
request.setError(error);
// Send the batched response
batchResponse(cacheKey, request);
}
}
可以重写这2个接口,进行本地的保存操作.ImageLoader的源码简单的介绍到这里.接下来看如何在原有基础上增加一些拓展功能.
package com.chediandian.core.image;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import com.android.volley.RequestQueue;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.ImageLoader;
import com.chediandian.core.image.cache.LruBitmapCache;
import com.chediandian.core.image.cache.local.name.LocalName;
import com.chediandian.core.image.utils.XKImageUtils;
/**
* <p>
* <b>ImageLoader增强版</b>
* </p>
* <li>支持本地缓存</li> <li>支持取消指定的图片请求</li> <li>比之前更强大的内存缓存池</li>
*
* @version 1.0
* @since 1.0
* @author Shun
* @hide 暂时不对外不暴露
*
*/
class XKImageLoader extends ImageLoader {
private LruBitmapCache mCache;
private LocalName mLocalName;
private String mLocalDirsPath;
private ExecutorService mPool;
private Map<String, ImageContainer> mRequests;
/**
*
* @param queue
* @param imageCache
* @param localDirsPath
* 本地缓存文件夹路径
* @param localName
* 文件名策略接口
*/
public XKImageLoader(RequestQueue queue, ImageCache imageCache,
String localDirsPath, LocalName localName) {
super(queue, imageCache);
// 这里记录引用,为了添加本地缓存
mCache = (LruBitmapCache) imageCache;
mLocalDirsPath = localDirsPath;
mLocalName = localName;
mPool = Executors.newFixedThreadPool(2);
mRequests = new ConcurrentHashMap<String, ImageContainer>();
}
/**
* 复写get方法,增加本地是否有缓存的逻辑
*/
@Override
public ImageContainer get(String requestUrl, ImageListener imageListener,
int maxWidth, int maxHeight) {
String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight);
// 不在缓存,则从本地找
if (mCache.getBitmap(cacheKey) == null) {
File file = new File(mLocalDirsPath,
mLocalName.getFileName(cacheKey));
// 如果缓存文件存在,那么加入到缓存
if (file.exists()) {
mPool.execute(new LoadLocalTask(cacheKey, file
.getAbsolutePath(), requestUrl, imageListener,
maxWidth, maxHeight));
return null;
}
}
ImageContainer container = super.get(requestUrl, imageListener,
maxWidth, maxHeight);
// 如果bitmap为空,表示容器中没有缓存,即把它添加到请求Map中
if (null == container.getBitmap()) {
mRequests.put(cacheKey, container);
}
return container;
}
/**
* 加载本地图片
*
* @param path
* 图片路径
* @param imageListener
* 图片监听
* @param maxWidth
* 最大宽度
* @param maxHeight
* 最大高度
*/
public void loadImage(String path, ImageListener imageListener,
int maxWidth, int maxHeight) {
String key = getCacheKey(path, maxWidth, maxHeight);
// 不在缓存,则从本地找
if (mCache.getBitmap(key) == null) {
File file = new File(path);
// 如果缓存文件存在,那么加入到缓存
if (file.exists()) {
mPool.execute(new LoadLocalTask(key, file.getAbsolutePath(),
path, imageListener, maxWidth, maxHeight));
}
} else {
Bitmap bitmap = mCache.getBitmap(key);
ImageContainer container = new ImageContainer(bitmap, path, null,
null);
imageListener.onResponse(container, true);
}
}
/**
* 复写onGetImageSuccess,增加线程池来管理持久化
*/
@Override
protected void onGetImageSuccess(String cacheKey, Bitmap response) {
// 持久化图片缓存
File file = new File(mLocalDirsPath, mLocalName.getFileName(cacheKey));
if (!file.exists()) {
mPool.execute(new LocalTask(file.getAbsolutePath(), response));
}
super.onGetImageSuccess(cacheKey, response);
// 从请求Map中移除这条请求,因为它已经完成
mRequests.remove(cacheKey);
}
@Override
protected void onGetImageError(String cacheKey, VolleyError error) {
super.onGetImageError(cacheKey, error);
// 从请求Map中移除这条请求,因为它已经完成
mRequests.remove(cacheKey);
}
/**
* <p>
* <b>持久化图片到本地的Task</b>
* </P>
*
* @version 1.0
* @since 1.0
* @author Shun
*
*/
private class LocalTask implements Runnable {
private String mPath;
private Bitmap mBitmap;
public LocalTask(String path, Bitmap bitmap) {
this.mPath = path;
this.mBitmap = bitmap;
}
@Override
public void run() {
FileOutputStream out = null;
try {
if (null != mBitmap) {
out = new FileOutputStream(mPath);
mBitmap.compress(CompressFormat.JPEG, 100, out);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
out = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
/**
* 加载本地图片Task
*
* @version 1.0
* @since 1.0
* @author Shun
*
*/
private class LoadLocalTask implements Runnable {
String mCacheKey;
String mPath;
String mUrl;
ImageListener mImageListener;
int mWidth;
int mHeight;
public LoadLocalTask(String cacheKey, String path, String url,
ImageListener imageListener, int width, int height) {
this.mCacheKey = cacheKey;
this.mPath = path;
this.mUrl = url;
this.mImageListener = imageListener;
this.mWidth = width;
this.mHeight = height;
}
@Override
public void run() {
Bitmap bitmap = XKImageUtils.loadBitmap(mPath, mWidth, mHeight);
if (null != bitmap) {
mCache.putBitmap(mCacheKey, bitmap);
}
// 这个Hanlder是父类的全局变量
mHandler.postDelayed(new DeliverTask(bitmap, mUrl, mImageListener),
100);
}
}
/**
* 转发到主线程的Task
*
* @version 1.0
* @since 1.0
* @author Shun
*
*/
private class DeliverTask implements Runnable {
Bitmap mCacheBitmap;
String mUrl;
ImageListener mImageListener;
public DeliverTask(Bitmap cacheBitmap, String url,
ImageListener imageListener) {
this.mCacheBitmap = cacheBitmap;
this.mUrl = url;
this.mImageListener = imageListener;
}
@Override
public void run() {
ImageContainer container = new ImageContainer(mCacheBitmap, mUrl,
null, null);
if (null != mCacheBitmap)
mImageListener.onResponse(container, true);
else
mImageListener.onErrorResponse(null);
}
}
/**
*
* <p>
* <b>取消所有图片请求</b>
* </p>
* 注意的是,此类接口对本地图片无效
*/
public void cancelRequest() {
for (String key : mRequests.keySet()) {
ImageContainer container = mRequests.get(key);
if (null != container)
container.cancelRequest();
}
mRequests.clear();
}
/**
*
* <p>
* <b>取消指定的请求</b>
* </p>
*
* @param url
* 请求的URL
*/
public void cancelRequest(String url) {
cancelRequest(url, 0, 0);
}
/**
*
* <p>
* <b>取消指定的请求</b>
* </p>
*
* @param url
* 请求的URL
* @param maxWidth
* 加载时设置的宽度
* @param maxHeight
* 加载时设置的高度
*/
public void cancelRequest(String url, int maxWidth, int maxHeight) {
String key = getCacheKey(url, maxWidth, maxHeight);
ImageContainer container = mRequests.remove(key);
if (null != container) {
container.cancelRequest();
}
}
/**
*
* <p>
* <b>清除所有缓存</b>
* </p>
*/
public void clearCache() {
if (null != mCache) {
mCache.clear();
}
}
/**
*
* <p>
* <b>清除指定缓存</b>
* </p>
*
* @param urlOrPath
* 可以是Url可以是本地路径
*/
public boolean cearCache(String urlOrPath) {
return clearCache(urlOrPath, 0, 0);
}
/**
*
* <p>
* <b>清除指定缓存</b>
* </p>
* 注意maxWidth,maxHeight必须与缓存请求时的大小保持一致
*
* @param urlOrPath
* 可以是Url可以是本地路径
* @param maxWidth
* 加载时设置的宽度
* @param maxHeight
* 加载时设置的高度
*/
public boolean clearCache(String urlOrPath, int maxWidth, int maxHeight) {
if (null != mCache) {
Bitmap bitmap = mCache.remove(getCacheKey(urlOrPath, maxWidth,
maxHeight));
if (null != bitmap) {
if (!bitmap.isRecycled()) {
bitmap.recycle();
}
bitmap = null;
return true;
} else {
return false;
}
}
return false;
}
}
可以看到 我重写了onGetImageSuccess,onGetImageError,get
3个接口来实现本地化功能.大家可以看一下,注释先的很清楚,DeliverTask主要用于异步加载本地图片后调度到主线程.LocalTask主要用于图片的持久化.LoadLocalTask加载本地图片.需要注意的是mHandler. mHandler在源码中是私有的.我自己改成了受保护的.
get接口中,会先检查是否有缓存,没有缓存的话从本地找,如果本地有的话会讲一个任务放到线程池中去执行. 最后由DeliverTask 调度到主线程中 关键代码:
String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight);
// 不在缓存,则从本地找
if (mCache.getBitmap(cacheKey) == null) {
File file = new File(mLocalDirsPath,
mLocalName.getFileName(cacheKey));
// 如果缓存文件存在,那么加入到缓存
if (file.exists()) {
mPool.execute(new LoadLocalTask(cacheKey, file
.getAbsolutePath(), requestUrl, imageListener,
maxWidth, maxHeight));
return null;
}
}
重写onGetImageSuccess的目的是为了在图片获取成功时将图片保存到本地
如果本地不存在,会执行一个持久化任务, 同样也是通过线程.
File file = new File(mLocalDirsPath, mLocalName.getFileName(cacheKey));
if (!file.exists()) {
mPool.execute(new LocalTask(file.getAbsolutePath(), response));
}
至此,一个支持本地功能的ImageLoader完成,看注释应该很容易看懂代码,这里就不细讲了 :)
先来看ImageLoader的关键源码:
public ImageContainer get(String requestUrl, ImageListener imageListener,
int maxWidth, int maxHeight) {
// only fulfill requests that were initiated from the main thread.
throwIfNotOnMainThread();
final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight);
// Try to look up the request in the cache of remote images.
Bitmap cachedBitmap = mCache.getBitmap(cacheKey);
if (cachedBitmap != null) {
// Return the cached bitmap.
ImageContainer container = new ImageContainer(cachedBitmap,
requestUrl, null, null);
imageListener.onResponse(container, true);
return container;
}
// The bitmap did not exist in the cache, fetch it!
ImageContainer imageContainer = new ImageContainer(null, requestUrl,
cacheKey, imageListener);
// Update the caller to let them know that they should use the default
// bitmap.
imageListener.onResponse(imageContainer, true);
// Check to see if a request is already in-flight.
BatchedImageRequest request = mInFlightRequests.get(cacheKey);
if (request != null) {
// If it is, add this request to the list of listeners.
request.addContainer(imageContainer);
return imageContainer;
}
// The request is not already in flight. Send the new request to the
// network and
// track it.
Request<Bitmap> newRequest = makeImageRequest(requestUrl, maxWidth,
maxHeight, cacheKey);
mRequestQueue.add(newRequest);
mInFlightRequests.put(cacheKey, new BatchedImageRequest(newRequest,
imageContainer));
return imageContainer;
}
这个是请求图片的接口,可以看到,他通过图片路径+高度+宽度生成了一个缓存的Key.然后会通过这个Key去mCache中查找是否有缓存图片.如果有的话,会直接直接把图片包装成一个ImageContainer.且直接返回,如果没有找找到的话.会生成一个一个请求,将这条请求入队.执行策略的话,内部是一个优先级的阻塞队列.而ImageRequest的优先级是low.在ImageRequest这个类的getPriority()接口会返回优先级.注意的是,onResponse接口的第二参数,表示是否是及时返回的.如果为true时,一般表示图片在内存中,所以一般如果参数为True的话,不用启动动画效果.为false的话表示进行了网络请求.这时即可对imageview进行一些动画的过度.
protected Request<Bitmap> makeImageRequest(String requestUrl, int maxWidth,
int maxHeight, final String cacheKey) {
return new ImageRequest(requestUrl, new Listener<Bitmap>() {
@Override
public void onResponse(Bitmap response) {
onGetImageSuccess(cacheKey, response);
}
}, maxWidth, maxHeight, Config.RGB_565, new ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
onGetImageError(cacheKey, error);
}
});
}
这个接口生产了一个ImageRequest对象.成功时会触发
protected void onGetImageSuccess(String cacheKey, Bitmap response) {
// cache the image that was fetched.
mCache.putBitmap(cacheKey, response);
// remove the request from the list of in-flight requests.
BatchedImageRequest request = mInFlightRequests.remove(cacheKey);
if (request != null) {
// Update the response bitmap.
request.mResponseBitmap = response;
// Send the batched response
batchResponse(cacheKey, request);
}
}
失败时会触发
protected void onGetImageError(String cacheKey, VolleyError error) {
// Notify the requesters that something failed via a null result.
// Remove this request from the list of in-flight requests.
BatchedImageRequest request = mInFlightRequests.remove(cacheKey);
if (request != null) {
// Set the error for this request
request.setError(error);
// Send the batched response
batchResponse(cacheKey, request);
}
}
可以重写这2个接口,进行本地的保存操作.ImageLoader的源码简单的介绍到这里.接下来看如何在原有基础上增加一些拓展功能.
package com.chediandian.core.image;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import com.android.volley.RequestQueue;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.ImageLoader;
import com.chediandian.core.image.cache.LruBitmapCache;
import com.chediandian.core.image.cache.local.name.LocalName;
import com.chediandian.core.image.utils.XKImageUtils;
/**
* <p>
* <b>ImageLoader增强版</b>
* </p>
* <li>支持本地缓存</li> <li>支持取消指定的图片请求</li> <li>比之前更强大的内存缓存池</li>
*
* @version 1.0
* @since 1.0
* @author Shun
* @hide 暂时不对外不暴露
*
*/
class XKImageLoader extends ImageLoader {
private LruBitmapCache mCache;
private LocalName mLocalName;
private String mLocalDirsPath;
private ExecutorService mPool;
private Map<String, ImageContainer> mRequests;
/**
*
* @param queue
* @param imageCache
* @param localDirsPath
* 本地缓存文件夹路径
* @param localName
* 文件名策略接口
*/
public XKImageLoader(RequestQueue queue, ImageCache imageCache,
String localDirsPath, LocalName localName) {
super(queue, imageCache);
// 这里记录引用,为了添加本地缓存
mCache = (LruBitmapCache) imageCache;
mLocalDirsPath = localDirsPath;
mLocalName = localName;
mPool = Executors.newFixedThreadPool(2);
mRequests = new ConcurrentHashMap<String, ImageContainer>();
}
/**
* 复写get方法,增加本地是否有缓存的逻辑
*/
@Override
public ImageContainer get(String requestUrl, ImageListener imageListener,
int maxWidth, int maxHeight) {
String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight);
// 不在缓存,则从本地找
if (mCache.getBitmap(cacheKey) == null) {
File file = new File(mLocalDirsPath,
mLocalName.getFileName(cacheKey));
// 如果缓存文件存在,那么加入到缓存
if (file.exists()) {
mPool.execute(new LoadLocalTask(cacheKey, file
.getAbsolutePath(), requestUrl, imageListener,
maxWidth, maxHeight));
return null;
}
}
ImageContainer container = super.get(requestUrl, imageListener,
maxWidth, maxHeight);
// 如果bitmap为空,表示容器中没有缓存,即把它添加到请求Map中
if (null == container.getBitmap()) {
mRequests.put(cacheKey, container);
}
return container;
}
/**
* 加载本地图片
*
* @param path
* 图片路径
* @param imageListener
* 图片监听
* @param maxWidth
* 最大宽度
* @param maxHeight
* 最大高度
*/
public void loadImage(String path, ImageListener imageListener,
int maxWidth, int maxHeight) {
String key = getCacheKey(path, maxWidth, maxHeight);
// 不在缓存,则从本地找
if (mCache.getBitmap(key) == null) {
File file = new File(path);
// 如果缓存文件存在,那么加入到缓存
if (file.exists()) {
mPool.execute(new LoadLocalTask(key, file.getAbsolutePath(),
path, imageListener, maxWidth, maxHeight));
}
} else {
Bitmap bitmap = mCache.getBitmap(key);
ImageContainer container = new ImageContainer(bitmap, path, null,
null);
imageListener.onResponse(container, true);
}
}
/**
* 复写onGetImageSuccess,增加线程池来管理持久化
*/
@Override
protected void onGetImageSuccess(String cacheKey, Bitmap response) {
// 持久化图片缓存
File file = new File(mLocalDirsPath, mLocalName.getFileName(cacheKey));
if (!file.exists()) {
mPool.execute(new LocalTask(file.getAbsolutePath(), response));
}
super.onGetImageSuccess(cacheKey, response);
// 从请求Map中移除这条请求,因为它已经完成
mRequests.remove(cacheKey);
}
@Override
protected void onGetImageError(String cacheKey, VolleyError error) {
super.onGetImageError(cacheKey, error);
// 从请求Map中移除这条请求,因为它已经完成
mRequests.remove(cacheKey);
}
/**
* <p>
* <b>持久化图片到本地的Task</b>
* </P>
*
* @version 1.0
* @since 1.0
* @author Shun
*
*/
private class LocalTask implements Runnable {
private String mPath;
private Bitmap mBitmap;
public LocalTask(String path, Bitmap bitmap) {
this.mPath = path;
this.mBitmap = bitmap;
}
@Override
public void run() {
FileOutputStream out = null;
try {
if (null != mBitmap) {
out = new FileOutputStream(mPath);
mBitmap.compress(CompressFormat.JPEG, 100, out);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
out = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
/**
* 加载本地图片Task
*
* @version 1.0
* @since 1.0
* @author Shun
*
*/
private class LoadLocalTask implements Runnable {
String mCacheKey;
String mPath;
String mUrl;
ImageListener mImageListener;
int mWidth;
int mHeight;
public LoadLocalTask(String cacheKey, String path, String url,
ImageListener imageListener, int width, int height) {
this.mCacheKey = cacheKey;
this.mPath = path;
this.mUrl = url;
this.mImageListener = imageListener;
this.mWidth = width;
this.mHeight = height;
}
@Override
public void run() {
Bitmap bitmap = XKImageUtils.loadBitmap(mPath, mWidth, mHeight);
if (null != bitmap) {
mCache.putBitmap(mCacheKey, bitmap);
}
// 这个Hanlder是父类的全局变量
mHandler.postDelayed(new DeliverTask(bitmap, mUrl, mImageListener),
100);
}
}
/**
* 转发到主线程的Task
*
* @version 1.0
* @since 1.0
* @author Shun
*
*/
private class DeliverTask implements Runnable {
Bitmap mCacheBitmap;
String mUrl;
ImageListener mImageListener;
public DeliverTask(Bitmap cacheBitmap, String url,
ImageListener imageListener) {
this.mCacheBitmap = cacheBitmap;
this.mUrl = url;
this.mImageListener = imageListener;
}
@Override
public void run() {
ImageContainer container = new ImageContainer(mCacheBitmap, mUrl,
null, null);
if (null != mCacheBitmap)
mImageListener.onResponse(container, true);
else
mImageListener.onErrorResponse(null);
}
}
/**
*
* <p>
* <b>取消所有图片请求</b>
* </p>
* 注意的是,此类接口对本地图片无效
*/
public void cancelRequest() {
for (String key : mRequests.keySet()) {
ImageContainer container = mRequests.get(key);
if (null != container)
container.cancelRequest();
}
mRequests.clear();
}
/**
*
* <p>
* <b>取消指定的请求</b>
* </p>
*
* @param url
* 请求的URL
*/
public void cancelRequest(String url) {
cancelRequest(url, 0, 0);
}
/**
*
* <p>
* <b>取消指定的请求</b>
* </p>
*
* @param url
* 请求的URL
* @param maxWidth
* 加载时设置的宽度
* @param maxHeight
* 加载时设置的高度
*/
public void cancelRequest(String url, int maxWidth, int maxHeight) {
String key = getCacheKey(url, maxWidth, maxHeight);
ImageContainer container = mRequests.remove(key);
if (null != container) {
container.cancelRequest();
}
}
/**
*
* <p>
* <b>清除所有缓存</b>
* </p>
*/
public void clearCache() {
if (null != mCache) {
mCache.clear();
}
}
/**
*
* <p>
* <b>清除指定缓存</b>
* </p>
*
* @param urlOrPath
* 可以是Url可以是本地路径
*/
public boolean cearCache(String urlOrPath) {
return clearCache(urlOrPath, 0, 0);
}
/**
*
* <p>
* <b>清除指定缓存</b>
* </p>
* 注意maxWidth,maxHeight必须与缓存请求时的大小保持一致
*
* @param urlOrPath
* 可以是Url可以是本地路径
* @param maxWidth
* 加载时设置的宽度
* @param maxHeight
* 加载时设置的高度
*/
public boolean clearCache(String urlOrPath, int maxWidth, int maxHeight) {
if (null != mCache) {
Bitmap bitmap = mCache.remove(getCacheKey(urlOrPath, maxWidth,
maxHeight));
if (null != bitmap) {
if (!bitmap.isRecycled()) {
bitmap.recycle();
}
bitmap = null;
return true;
} else {
return false;
}
}
return false;
}
}
可以看到 我重写了onGetImageSuccess,onGetImageError,get
3个接口来实现本地化功能.大家可以看一下,注释先的很清楚,DeliverTask主要用于异步加载本地图片后调度到主线程.LocalTask主要用于图片的持久化.LoadLocalTask加载本地图片.需要注意的是mHandler. mHandler在源码中是私有的.我自己改成了受保护的.
get接口中,会先检查是否有缓存,没有缓存的话从本地找,如果本地有的话会讲一个任务放到线程池中去执行. 最后由DeliverTask 调度到主线程中 关键代码:
String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight);
// 不在缓存,则从本地找
if (mCache.getBitmap(cacheKey) == null) {
File file = new File(mLocalDirsPath,
mLocalName.getFileName(cacheKey));
// 如果缓存文件存在,那么加入到缓存
if (file.exists()) {
mPool.execute(new LoadLocalTask(cacheKey, file
.getAbsolutePath(), requestUrl, imageListener,
maxWidth, maxHeight));
return null;
}
}
重写onGetImageSuccess的目的是为了在图片获取成功时将图片保存到本地
如果本地不存在,会执行一个持久化任务, 同样也是通过线程.
File file = new File(mLocalDirsPath, mLocalName.getFileName(cacheKey));
if (!file.exists()) {
mPool.execute(new LocalTask(file.getAbsolutePath(), response));
}
至此,一个支持本地功能的ImageLoader完成,看注释应该很容易看懂代码,这里就不细讲了 :)
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories