import com.jason.imageloader.cache.BitmapCache;
import com.jason.imageloader.config.DisplayConfig;
import com.jason.imageloader.core.SimpleImageLoader;
import com.jason.imageloader.request.BitmapRequest;
import android.graphics.Bitmap;
import android.widget.ImageView;
/**
* 抽象加载器
*/
public abstract class AbstractLoader implements Loader{
//缓存策略
private BitmapCache mCache = SimpleImageLoader.getObject().getConfig().getBitmapCache();
//显示配置
private DisplayConfig mDisplayConfig = SimpleImageLoader.getObject().getConfig().getDisplayConfig();
/**
* 模板方法
*/
@Override
public void loadImage(BitmapRequest request) {
//从缓存获取,缓存中没有再加载
Bitmap bitmap = mCache.get(request);
if(bitmap == null){
//加载前显示的图片
showLoadingImage(request);
//加载完成,再缓存
//具体的加载方式,由子类决定
bitmap = onLoad(request);
cacheBitmap(request,bitmap);
}
//显示
deliveryToUIThread(request, bitmap);
}
/**
* 加载前显示的图片
* @param request
*/
protected void showLoadingImage(BitmapRequest request) {
//指定了,显示配置
if(hasLoadingPlaceHolder()){
final ImageView imageView = request.getImageView();
imageView.post(new Runnable() {
@Override
public void run() {
imageView.setImageResource(mDisplayConfig.loadingImg);
}
});
}
}
protected boolean hasLoadingPlaceHolder(){
return (mDisplayConfig != null && mDisplayConfig.loadingImg > 0);
}
protected boolean hasFailedPlaceHolder(){
return (mDisplayConfig != null && mDisplayConfig.failedImg > 0);
}
/**
* 交给主线程显示
* @param request
* @param bitmap
*/
protected void deliveryToUIThread(final BitmapRequest request, final Bitmap bitmap) {
ImageView imageView = request.getImageView();
imageView.post(new Runnable() {
@Override
public void run() {
updateImageView(request, bitmap);
}
});
}
private void updateImageView(final BitmapRequest request, final Bitmap bitmap) {
ImageView imageView = request.getImageView();
//加载正常
if(bitmap != null && imageView.getTag().equals(request.getImageUri())){
imageView.setImageBitmap(bitmap);
}
//有可能加载失败
if(bitmap == null && hasFailedPlaceHolder()){
imageView.setImageResource(mDisplayConfig.failedImg);
}
//监听
//回调
if(request.imageListener != null){
request.imageListener.onComplete(imageView, bitmap, request.getImageUri());
}
}
/**
* 缓存
* @param request
* @param bitmap
*/
private void cacheBitmap(BitmapRequest request, Bitmap bitmap) {
if(request != null && bitmap != null){
synchronized (mCache) {
mCache.put(request,bitmap);
}
}
}
/**
* 具体的加载实现
* @param request
* @return
*/
protected abstract Bitmap onLoad(BitmapRequest request);
}
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import com.jason.imageloader.request.BitmapRequest;
import com.jason.imageloader.utils.BitmapDecoder;
import com.jason.imageloader.utils.ImageViewHelper;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
/**
* 网络图片加载器
*/
public class UrlLoader extends AbstractLoader {
@Override
protected Bitmap onLoad(BitmapRequest request) {
HttpURLConnection connection = null;
InputStream in = null;
try {
connection = (HttpURLConnection)new URL(request.getImageUri()).openConnection();
//mark与reset支持重复使用流,但是InputStream不支持
in = new BufferedInputStream(connection.getInputStream());
//标记
in.mark(in.available());
final InputStream inputStream = in;
//匿名内部类
BitmapDecoder decoder = new BitmapDecoder(){
@Override
public Bitmap decodeBitmapWithOption(Options options) {
Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, options);
if(options.inJustDecodeBounds){
try {
//重置
//则输入流总会在调用 mark 之后记住所有读取的字节,并且无论何时调用方法 reset ,都会准备再次提供那些相同的字节
//但是,如果在调用 reset 之前可以从流中读取多于 readlimit 的字节,则根本不需要该流记住任何数据。
inputStream.reset();
} catch (Exception e) {
e.printStackTrace();
}
}else{
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return bitmap;
}
};
//如何获取ImageView的宽高?
return decoder.decodeBitmap(ImageViewHelper.getImageViewWidth(request.getImageView()), ImageViewHelper.getImageViewHeight(request.getImageView()));
} catch (Exception e) {
e.printStackTrace();
} finally{
if(connection != null){
connection.disconnect();
}
try {
if(in != null){
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
/**
* 图片压缩器
*/
public abstract class BitmapDecoder {
public abstract Bitmap decodeBitmapWithOption(Options options);
/**
* 压缩图片
* @param reqWidth 指定要缩放后的宽度
* @param reqHeight 指定要缩放后的高度
* @return
*/
public Bitmap decodeBitmap(int reqWidth,int reqHeight){
//1.初始化Options
BitmapFactory.Options options = new BitmapFactory.Options();
//Bitmap对象不占用内存
//只需要读取图片的宽高信息,无需将整张图片加载到内存中
options.inJustDecodeBounds = true;
//2.根据options加载Bitmap,图片的数据存储在options中(第一次读取图片的宽高)
decodeBitmapWithOption(options);
//3.计算图片缩放的比例
calculateSampleSizeWithOption(options,reqWidth,reqHeight);
//4.通过options设置的缩放比例记载图片(第二次根据缩放比例读取一个缩放后的图片)
return decodeBitmapWithOption(options);
}
/**
* 计算图片缩放的比例
* @param options
* @param reqWidth
* @param reqHeight
*/
private void calculateSampleSizeWithOption(Options options, int reqWidth, int reqHeight) {
//计算缩放的比例
//图片的原始宽高
int width = options.outWidth;
int height = options.outHeight;
int inSampleSize = 1;
if(width > reqWidth || height > reqHeight){
//宽高的缩放比例
int heightRatio = Math.round((float)height / (float)reqHeight);
int widthRatio = Math.round((float)width / (float)reqWidth);
//有的图是长图、有的是宽图
inSampleSize = Math.max(heightRatio, widthRatio);
}
//全景图
//当inSampleSize为2,图片的宽与高变成原来的1/2
//options.inSampleSize = 2
options.inSampleSize = inSampleSize;
//每个像素2个字节
options.inPreferredConfig = Config.RGB_565;
//Bitmap占用内存
options.inJustDecodeBounds = false;
//当系统内存不足时可以回收Bitmap
options.inPurgeable = true;
options.inInputShareable = true;
}
}
整理自课程