原:http://www.cnblogs.com/angeldevil/archive/2012/09/16/2687174.htmlhtml
相关:https://github.com/nostra13/Android-Universal-Image-Loaderandroid
开发Android程序,通常状况下都会有两个操做,图片的异步加载与缓存,而图片的异步加载大都是从网络读取图片(还有生成本地图片缩略图等操做),为了减小网络操做,加快图片加载速度就须要对图片进行缓存,因此网上的好多图片异步加载方法都是与图片的缓存紧密关联的。但也有可能用户已经有了缓存的相关类库,这样使用起来就会有点麻烦。git
最近一段处理跟图片相关的问题,原本是本身写的图片加载,不过有些状态的控制仍是比较烦人的,好比ListView滚动时ImageView的重用,因此本着偷懒与充分利用现有资源的态度去网上搜罗图片异步加载的代码,最终在GreenDroid UI库中找到一个,其中有个AsyncImageView的自定义View用于异步加载图片,不过也像网上的大多数图片异步加载方法同样,是跟图片的缓存关联在一块儿的,不过只是很简单的内存缓存,无文件缓存。图片的加载方法也如其余的同样是写死了的,这就限制了其使用范围,只可经过InputStream来decode图片,而像生成缩略图或其余一些图片处理的异步处理就没法用途。修改现有类库总比本身从头写来的简单,因而稍微修改了下AsyncImageView,使其能够自定义缓存与图片加载方法,对于AsyncImageView只有一点点的修改,大都是别人源码。github
public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); final Handler h = mHandler; Bitmap bitmap = null; Throwable throwable = null; h.sendMessage(Message.obtain(h, ON_START)); try { if (TextUtils.isEmpty(mUrl)) { throw new Exception("The given URL cannot be null or empty"); } // 若是自定义了加载方法,则用自定义的方法 if (mLoadMethod != null) { bitmap = mLoadMethod.load(mUrl); } else { InputStream inputStream = null; // Asset if (mUrl.startsWith("file:///android_asset/")) { inputStream = sAssetManager.open(mUrl.replaceFirst( "file:///android_asset/", "")); } // File else if (mUrl.startsWith("file:///") || mUrl.startsWith("/")) { if (mUrl.startsWith("file:///")) mUrl = mUrl.replaceFirst("file:///", "/"); inputStream = new FileInputStream(mUrl); } // NetWork else { // 在用URL类加载图片时,发现有的机型上面经过URL类得到的InputStream解析得到的图片老是null,故使用HttpClient HttpGet httpRequest = new HttpGet(mUrl); HttpClient httpclient = new DefaultHttpClient(); HttpParams httpParams = new BasicHttpParams(); HttpConnectionParams.setConnectionTimeout(httpParams, 5000); HttpConnectionParams.setSoTimeout(httpParams, 5000); httpRequest.setParams(httpParams); HttpResponse response = (HttpResponse)httpclient.execute(httpRequest); HttpEntity entity = response.getEntity(); BufferedHttpEntity bufHttpEntity = new BufferedHttpEntity(entity); InputStream instream = bufHttpEntity.getContent(); BufferedInputStream bi = new BufferedInputStream(instream); inputStream = bi; } // 虽然AsyncImageView中有设置BitmapFactory.Options的方法,但通常状况下都未知图片的大小,也就没法计算相应的inSampleSize, // 也就没法设置相应的BitmapFactory.Options,因此通常状况下仍是根据本身的须要自定义LoadMethod为好 bitmap = BitmapFactory.decodeStream(inputStream, null, (mOptions == null) ? sDefaultOptions : mOptions); inputStream.close(); } if (mBitmapProcessor != null && bitmap != null) { final Bitmap processedBitmap = mBitmapProcessor.processImage(bitmap); if (processedBitmap != null) { bitmap.recycle(); bitmap = processedBitmap; } } } catch (Exception e) { Log.e(LOG_TAG, "Error while fetching image", e); throwable = e; } if (bitmap == null) { if (throwable == null) { throwable = new Exception("Skia image decoding failed"); } h.sendMessage(Message.obtain(h, ON_FAIL, throwable)); } else { h.sendMessage(Message.obtain(h, ON_END, bitmap)); if (mCache != null) { mCache.writeCache(TextUtils.isEmpty(mCacheKey) ? mUrl : mCacheKey, bitmap); } } }
若是自定义了LoadMethod,会调用相应的方法加载图片,若是没有自定义,会使用默认的加载方法,能够加载本地图片,Asset图片与网络图片,GreenDroid的源码中加载网络图片是用的URL的,但咱们之前在加载网络图片时遇到一个问题,有的机型经过URL类得到的ImputStream解析图片老是返回null,因此就改成了HttpClient。缓存
经过AsyncImageView的setPath方法来加载图片,setPath有3个重载方法:网络
第一个参数指定要加载的图片的路径,第二个参数为自定义的图片加载方法,若不指定则用默认的。异步
至于加第三个参数,是作缓存用的,通常要加载的图片的路径都是惟一的,因此通常用第一个参数来作为缓存的Key就好了,但也有特殊状况,好比读取局域网中的图片,通常都是自动获取IP,因此根据图片路径作为缓存的Key多是不合适的,因此就须要根据须要手动指定用来做为缓存的Key。fetch
/** * 设置要加载的图片的路径, 可为网络路径, Asset文件路径(file:///android_asset), 本地图片路径(file:///或/) * * @param path 要加载的图片的路径, 若为null则加载默认图片 * @param loadMethod 自定义的图片加载的方法, 能够null, 使用默认的加载方法 * @param cacheKey 缓存key */ public void setPath(String path, LoadMethod loadMethod, String cacheKey) { // Check the url has changed if (mBitmap != null && path != null && path.equals(mUrl)) { // TODO mBitmap != null necessary? return; } stopLoading(); mUrl = path; mCacheKey = cacheKey; mLoadMethod = loadMethod; // Setting the url to an empty string force the displayed image to the // default image if (TextUtils.isEmpty(mUrl)) { mBitmap = null; setDefaultImage(); } else { if (!mPaused) { reload(); } else { // We're paused: let's look in a synchronous and efficient cache // prior using the default image. mBitmap = readCache(); // TODO 可能会耗时间 if (mBitmap != null) { setImageBitmap(mBitmap); } else { setDefaultImage(); } } } }
public void reload(boolean force) { if (mRequest == null && mUrl != null) { // Prior downloading the image ... let's look in a cache ! mBitmap = null; if (!force) { // This may take a long time. mBitmap = readCache(); } if (mBitmap != null) { setImageBitmap(mBitmap); return; } setDefaultImage(); mRequest = new ImageRequest(mUrl, this, mImageProcessor, mOptions, mCacheKey); mRequest.load(getContext(), mLoadMethod); if (ImageLoader.getInstance() != null && ImageLoader.getInstance().getCache() == null) { ImageLoader.getInstance().setCache(mCache); } }
readCache()用于读取缓存,代码以下:this
private Bitmap readCache() { if (mCache != null) return mCache.readCache(TextUtils.isEmpty(mCacheKey) ? mUrl : mCacheKey); return null; }
其中的mCache由用户能过setCacheCallback(CacheCallback callback)设置用户自定义的缓存方法,由此将图片的加载与缓存分离开,使用户能够使用现有的缓存实现。如要用户指定了缓存Key就使用用户指定的Key,不然就用图片的路径做Key。url
源码下载:AsyncImage