package reco.frame.tv;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import reco.frame.tv.bitmap.core.BitmapCache;
import reco.frame.tv.bitmap.core.BitmapDisplayConfig;
import reco.frame.tv.bitmap.core.BitmapProcess;
import reco.frame.tv.bitmap.display.Displayer;
import reco.frame.tv.bitmap.display.SimpleDisplayer;
import reco.frame.tv.bitmap.download.Downloader;
import reco.frame.tv.bitmap.download.SimpleDownloader;
import reco.frame.tv.core.AsyncTask;
import reco.frame.tv.util.Utils;
import android.R;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
public class TvBitmap {
private TvBitmapConfig mConfig;
private BitmapCache mImageCache;
private BitmapProcess mBitmapProcess;
private boolean mExitTasksEarly = false;
private boolean mPauseWork = false;
private final Object mPauseWorkLock = new Object();
private Context mContext;
private boolean mInit = false;
private ExecutorService bitmapLoadAndDisplayExecutor;
private static TvBitmap mTvBitmap;
private TvBitmap(Context context) {
mContext = context;
mConfig = new TvBitmapConfig(context);
configDiskCachePath(Utils.getDiskCacheDir(context, "afinalCache")
.getAbsolutePath());// 配置缓存路径
configDisplayer(new SimpleDisplayer());// //配置显示器
configDownlader(new SimpleDownloader());// //配置下载器
}
/**
* 创建单例
*
* @param ctx
* @return
*/
public static synchronized TvBitmap create(Context ctx) {
if (mTvBitmap==null) {
mTvBitmap = new TvBitmap(ctx.getApplicationContext());
}
return mTvBitmap;
}
/**
* 设置统一加载图
*
* @param bitmap
*/
public TvBitmap configLoadingImage(int resId) {
mConfig.defaultDisplayConfig.setLoadingRes(resId);
return this;
}
/**
* 设置统一加载失败图
*
* @param bitmap
*/
public TvBitmap configLoadfailImage(Bitmap bitmap) {
mConfig.defaultDisplayConfig.setLoadfailBitmap(bitmap);
return this;
}
/**
* 设置统一加载失败图
*
* @param resId
*/
public TvBitmap configLoadfailImage(int resId) {
mConfig.defaultDisplayConfig.setLoadfailBitmap(BitmapFactory
.decodeResource(mContext.getResources(), resId));
return this;
}
/**
* 设置图片最大高度
*
* @param bitmapHeight
*/
public TvBitmap configBitmapMaxHeight(int bitmapHeight) {
mConfig.defaultDisplayConfig.setBitmapHeight(bitmapHeight);
return this;
}
/**
* 设置图片最大宽度
*
* @param bitmapHeight
*/
public TvBitmap configBitmapMaxWidth(int bitmapWidth) {
mConfig.defaultDisplayConfig.setBitmapWidth(bitmapWidth);
return this;
}
/**
* 设置下载器,比如通过ftp或者其他协议去网络读取图片的时候可以设置这项
*
* @param downlader
* @return
*/
public TvBitmap configDownlader(Downloader downlader) {
mConfig.downloader = downlader;
return this;
}
/**
* 设置显示器,比如在显示的过程中显示动画等
*
* @param displayer
* @return
*/
public TvBitmap configDisplayer(Displayer displayer) {
mConfig.displayer = displayer;
return this;
}
/**
* 配置磁盘缓存路径
*
* @param strPath
* @return
*/
public TvBitmap configDiskCachePath(String strPath) {
if (!TextUtils.isEmpty(strPath)) {
mConfig.cachePath = strPath;
}
return this;
}
/**
* 配置内存缓存大小 大于2MB以上有效
*
* @param size
* 缓存大小
*/
public TvBitmap configMemoryCacheSize(int size) {
mConfig.memCacheSize = size;
return this;
}
/**
* 设置应缓存的在APK总内存的百分比,优先级大于configMemoryCacheSize
*
* @param percent
*/
public TvBitmap configMemoryCachePercent(float percent) {
mConfig.memCacheSizePercent = percent;
return this;
}
/**
* 设置磁盘缓存大小 5MB 以上有效
*
* @param size
*/
public TvBitmap configDiskCacheSize(int size) {
mConfig.diskCacheSize = size;
return this;
}
/**
* 设置加载线程并发数量
*
* @param size
*/
public TvBitmap configBitmapLoadThreadSize(int size) {
if (size >= 1)
mConfig.poolSize = size;
return this;
}
/**
* 配置是否立即回收图片资源
*
* @param recycleImmediately
* @return
*/
public TvBitmap configRecycleImmediately(boolean recycleImmediately) {
mConfig.recycleImmediately = recycleImmediately;
return this;
}
/**
* 初始化
*
* @return
*/
private TvBitmap init() {
if (!mInit) {
BitmapCache.ImageCacheParams imageCacheParams = new BitmapCache.ImageCacheParams(
mConfig.cachePath);
if (mConfig.memCacheSizePercent > 0.05
&& mConfig.memCacheSizePercent < 0.8) {
imageCacheParams.setMemCacheSizePercent(mContext,
mConfig.memCacheSizePercent);
} else {
if (mConfig.memCacheSize > 1024 * 1024 * 2) {
imageCacheParams.setMemCacheSize(mConfig.memCacheSize);
} else {
// 设置默认的内存缓存大小
imageCacheParams.setMemCacheSizePercent(mContext, 0.3f);
}
}
if (mConfig.diskCacheSize > 1024 * 1024 * 5)
imageCacheParams.setDiskCacheSize(mConfig.diskCacheSize);
imageCacheParams.setRecycleImmediately(mConfig.recycleImmediately);
// init Cache
mImageCache = new BitmapCache(imageCacheParams);
// init Executors
bitmapLoadAndDisplayExecutor = Executors.newFixedThreadPool(
mConfig.poolSize, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
// 设置线程的优先级别,让线程先后顺序执行(级别越高,抢到cpu执行的时间越多)
t.setPriority(Thread.NORM_PRIORITY - 1);
return t;
}
});
// init BitmapProcess
mBitmapProcess = new BitmapProcess(mConfig.downloader, mImageCache);
mInit = true;
}
return this;
}
public void display(View view, String uri) {
doDisplay(view, uri, null);
}
public void display(View view, String uri, int imageWidth, int imageHeight) {
BitmapDisplayConfig displayConfig = configMap.get(imageWidth + "_"
+ imageHeight);
if (displayConfig == null) {
displayConfig = getDisplayConfig();
displayConfig.setBitmapHeight(imageHeight);
displayConfig.setBitmapWidth(imageWidth);
configMap.put(imageWidth + "_" + imageHeight, displayConfig);
}
doDisplay(view, uri, displayConfig);
}
public void display(View view, String uri, int resId) {
Bitmap loadingBitmap = BitmapFactory.decodeResource(
mContext.getResources(), resId);
if (loadingBitmap == null) {
display(view, uri);
} else {
display(view, uri, loadingBitmap);
}
}
public void display(View view, String uri, Bitmap loadingBitmap) {
BitmapDisplayConfig displayConfig = configMap.get(String
.valueOf(loadingBitmap));
if (displayConfig == null) {
displayConfig = getDisplayConfig();
displayConfig.setLoadingBitmap(loadingBitmap);
configMap.put(String.valueOf(loadingBitmap), displayConfig);
}
doDisplay(view, uri, displayConfig);
}
public void display(View imageView, String uri, Bitmap loadingBitmap,
Bitmap laodfailBitmap) {
BitmapDisplayConfig displayConfig = configMap.get(String
.valueOf(loadingBitmap) + "_" + String.valueOf(laodfailBitmap));
if (displayConfig == null) {
displayConfig = getDisplayConfig();
displayConfig.setLoadingBitmap(loadingBitmap);
displayConfig.setLoadfailBitmap(laodfailBitmap);
configMap.put(
String.valueOf(loadingBitmap) + "_"
+ String.valueOf(laodfailBitmap), displayConfig);
}
doDisplay(imageView, uri, displayConfig);
}
public void display(View view, String uri, int imageWidth, int imageHeight,
Bitmap loadingBitmap, Bitmap laodfailBitmap) {
BitmapDisplayConfig displayConfig = configMap.get(imageWidth + "_"
+ imageHeight + "_" + String.valueOf(loadingBitmap) + "_"
+ String.valueOf(laodfailBitmap));
if (displayConfig == null) {
displayConfig = getDisplayConfig();
displayConfig.setBitmapHeight(imageHeight);
displayConfig.setBitmapWidth(imageWidth);
displayConfig.setLoadingBitmap(loadingBitmap);
displayConfig.setLoadfailBitmap(laodfailBitmap);
configMap.put(
imageWidth + "_" + imageHeight + "_"
+ String.valueOf(loadingBitmap) + "_"
+ String.valueOf(laodfailBitmap), displayConfig);
}
doDisplay(view, uri, displayConfig);
}
public void display(View view, String uri, BitmapDisplayConfig config) {
doDisplay(view, uri, config);
}
private void doDisplay(View view, String uri,
BitmapDisplayConfig displayConfig) {
if (!mInit) {
init();
}
if (TextUtils.isEmpty(uri) || view == null) {
return;
}
if (displayConfig == null)
displayConfig = mConfig.defaultDisplayConfig;
Bitmap bitmap = null;
if (mImageCache != null) {
bitmap = mImageCache.getBitmapFromMemoryCache(uri);
}
if (bitmap != null) {
if (view instanceof ImageView) {
((ImageView) view).setImageBitmap(bitmap);
} else {
view.setBackgroundDrawable(new BitmapDrawable(bitmap));
}
} else if (checkImageTask(uri, view)) {
final BitmapLoadAndDisplayTask task = new BitmapLoadAndDisplayTask(
view, displayConfig);
// 设置默认图片
final AsyncDrawable asyncDrawable = new AsyncDrawable(
mContext.getResources(), displayConfig.getLoadingBitmap(),
task);
if (view instanceof ImageView) {
((ImageView) view).setImageDrawable(asyncDrawable);
} else {
view.setBackgroundDrawable(asyncDrawable);
}
task.executeOnExecutor(bitmapLoadAndDisplayExecutor, uri);
}
}
private HashMap<String, BitmapDisplayConfig> configMap = new HashMap<String, BitmapDisplayConfig>();
private BitmapDisplayConfig getDisplayConfig() {
BitmapDisplayConfig config = new BitmapDisplayConfig(mContext);
config.setAnimation(mConfig.defaultDisplayConfig.getAnimation());
config.setAnimationType(mConfig.defaultDisplayConfig.getAnimationType());
config.setBitmapHeight(mConfig.defaultDisplayConfig.getBitmapHeight());
config.setBitmapWidth(mConfig.defaultDisplayConfig.getBitmapWidth());
config.setLoadfailBitmap(mConfig.defaultDisplayConfig
.getLoadfailBitmap());
config.setLoadingBitmap(mConfig.defaultDisplayConfig.getLoadingBitmap());
return config;
}
private void clearCacheInternalInBackgroud() {
if (mImageCache != null) {
mImageCache.clearCache();
}
}
private void clearDiskCacheInBackgroud() {
if (mImageCache != null) {
mImageCache.clearDiskCache();
}
}
private void clearCacheInBackgroud(String key) {
if (mImageCache != null) {
mImageCache.clearCache(key);
}
}
private void clearDiskCacheInBackgroud(String key) {
if (mImageCache != null) {
mImageCache.clearDiskCache(key);
}
}
/**
* 执行过此方法后,TvBitmap的缓存已经失效,建议通过TvBitmap.create()获取新的实例
*
* @author fantouch
*/
private void closeCacheInternalInBackgroud() {
if (mImageCache != null) {
mImageCache.close();
mImageCache = null;
mTvBitmap = null;
}
}
/**
* 网络加载bitmap
*
* @param data
* @return
*/
private Bitmap processBitmap(String uri, BitmapDisplayConfig config) {
if (mBitmapProcess != null) {
return mBitmapProcess.getBitmap(uri, config);
}
return null;
}
/**
* 从缓存(内存缓存和磁盘缓存)中直接获取bitmap,注意此处有io操作,不可置于ui线程执行
*
* @param key
* @return
*/
public Bitmap getBitmapFromCache(String key) {
Bitmap bitmap = getBitmapFromMemoryCache(key);
if (bitmap == null)
bitmap = getBitmapFromDiskCache(key);
return bitmap;
}
/**
* 从内存缓存中获取bitmap
*
* @param key
* @return
*/
public Bitmap getBitmapFromMemoryCache(String key) {
return mImageCache.getBitmapFromMemoryCache(key);
}
/**
* 从磁盘缓存中获取bitmap
*
* @param key
* @return
*/
public Bitmap getBitmapFromDiskCache(String key) {
return getBitmapFromDiskCache(key, null);
}
public Bitmap getBitmapFromDiskCache(String key, BitmapDisplayConfig config) {
return mBitmapProcess.getFromDisk(key, config);
}
public void setExitTasksEarly(boolean exitTasksEarly) {
mExitTasksEarly = exitTasksEarly;
}
/**
* activity onResume的时候调用这个方法,让加载图片线程继续
*/
public void onResume() {
setExitTasksEarly(false);
}
/**
* activity onPause的时候调用这个方法,让线程暂停
*/
public void onPause() {
setExitTasksEarly(true);
}
/**
* activity onDestroy的时候调用这个方法,释放缓存
* 执行过此方法后,TvBitmap的缓存将失效,建议通过TvBitmap.create()获取新的实例
*
* @author fantouch
*/
public void onDestroy() {
closeCache();
}
/**
* 清除所有缓存(磁盘和内存)
*/
public void clearCache() {
new CacheExecutecTask().execute(CacheExecutecTask.MESSAGE_CLEAR);
}
/**
* 根据key清除指定的内存缓存
*
* @param key
*/
public void clearCache(String key) {
new CacheExecutecTask().execute(CacheExecutecTask.MESSAGE_CLEAR_KEY,
key);
}
/**
* 清除缓存
*/
public void clearMemoryCache() {
if (mImageCache != null)
mImageCache.clearMemoryCache();
}
/**
* 根据key清除指定的内存缓存
*
* @param key
*/
public void clearMemoryCache(String key) {
if (mImageCache != null)
mImageCache.clearMemoryCache(key);
}
/**
* 清除磁盘缓存
*/
public void clearDiskCache() {
new CacheExecutecTask().execute(CacheExecutecTask.MESSAGE_CLEAR_DISK);
}
/**
* 根据key清除指定磁盘缓存
*
* @param key
*/
public void clearDiskCache(String key) {
new CacheExecutecTask().execute(
CacheExecutecTask.MESSAGE_CLEAR_KEY_IN_DISK, key);
}
/**
* 关闭缓存 执行过此方法后,TvBitmap的缓存已经失效,建议通过TvBitmap.create()获取新的实例
*
* @author fantouch
*/
public void closeCache() {
new CacheExecutecTask().execute(CacheExecutecTask.MESSAGE_CLOSE);
}
/**
* 退出正在加载的线程,程序退出的时候调用词方法
*
* @param exitTasksEarly
*/
public void exitTasksEarly(boolean exitTasksEarly) {
mExitTasksEarly = exitTasksEarly;
if (exitTasksEarly)
pauseWork(false);// ??????锟斤拷锟斤拷锟斤拷锟斤拷缁捐法锟斤拷锟�?锟斤拷锟斤拷
}
/**
* 暂停正在加载的线程,监听listview或者gridview正在滑动的时候条用词方法
*
* @param pauseWork
* true停止暂停线程,false继续线程
*/
public void pauseWork(boolean pauseWork) {
synchronized (mPauseWorkLock) {
mPauseWork = pauseWork;
if (!mPauseWork) {
mPauseWorkLock.notifyAll();
}
}
}
private static BitmapLoadAndDisplayTask getBitmapTaskFromImageView(
View imageView) {
if (imageView != null) {
Drawable drawable = null;
if (imageView instanceof ImageView) {
drawable = ((ImageView) imageView).getDrawable();
} else {
drawable = imageView.getBackground();
}
if (drawable instanceof AsyncDrawable) {
final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
return asyncDrawable.getBitmapWorkerTask();
}
}
return null;
}
/**
* 检测 imageView中是否已经有线程在运行
*
* @param data
* @param imageView
* @return true 没有 false 有线程在运行了
*/
public static boolean checkImageTask(Object data, View imageView) {
final BitmapLoadAndDisplayTask bitmapWorkerTask = getBitmapTaskFromImageView(imageView);
if (bitmapWorkerTask != null) {
final Object bitmapData = bitmapWorkerTask.data;
if (bitmapData == null || !bitmapData.equals(data)) {
bitmapWorkerTask.cancel(true);
} else {
// 同一个线程已经在执行
return false;
}
}
return true;
}
private static class AsyncDrawable extends BitmapDrawable {
private final WeakReference<BitmapLoadAndDisplayTask> bitmapWorkerTaskReference;
public AsyncDrawable(Resources res, Bitmap bitmap,
BitmapLoadAndDisplayTask bitmapWorkerTask) {
super(res, bitmap);
bitmapWorkerTaskReference = new WeakReference<BitmapLoadAndDisplayTask>(
bitmapWorkerTask);
}
public BitmapLoadAndDisplayTask getBitmapWorkerTask() {
return bitmapWorkerTaskReference.get();
}
}
private class CacheExecutecTask extends AsyncTask<Object, Void, Void> {
public static final int MESSAGE_CLEAR = 1;
public static final int MESSAGE_CLOSE = 2;
public static final int MESSAGE_CLEAR_DISK = 3;
public static final int MESSAGE_CLEAR_KEY = 4;
public static final int MESSAGE_CLEAR_KEY_IN_DISK = 5;
@Override
protected Void doInBackground(Object... params) {
switch ((Integer) params[0]) {
case MESSAGE_CLEAR:
clearCacheInternalInBackgroud();
break;
case MESSAGE_CLOSE:
closeCacheInternalInBackgroud();
break;
case MESSAGE_CLEAR_DISK:
clearDiskCacheInBackgroud();
break;
case MESSAGE_CLEAR_KEY:
clearCacheInBackgroud(String.valueOf(params[1]));
break;
case MESSAGE_CLEAR_KEY_IN_DISK:
clearDiskCacheInBackgroud(String.valueOf(params[1]));
break;
}
return null;
}
}
/**
* bitmap下载显示的线程
*
* @author michael yang
*/
private class BitmapLoadAndDisplayTask extends
AsyncTask<Object, Void, Bitmap> {
private Object data;
private final WeakReference<View> imageViewReference;
private final BitmapDisplayConfig displayConfig;
public BitmapLoadAndDisplayTask(View imageView,
BitmapDisplayConfig config) {
imageViewReference = new WeakReference<View>(imageView);
displayConfig = config;
}
@Override
protected Bitmap doInBackground(Object... params) {
data = params[0];
final String dataString = String.valueOf(data);
Bitmap bitmap = null;
synchronized (mPauseWorkLock) {
while (mPauseWork && !isCancelled()) {
try {
mPauseWorkLock.wait();
} catch (InterruptedException e) {
}
}
}
if (bitmap == null && !isCancelled()
&& getAttachedImageView() != null && !mExitTasksEarly) {
bitmap = processBitmap(dataString, displayConfig);
}
if (bitmap != null) {
mImageCache.addToMemoryCache(dataString, bitmap);
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
if (isCancelled() || mExitTasksEarly) {
bitmap = null;
}
// 判断线程和当前的imageview是否是匹配
final View imageView = getAttachedImageView();
if (bitmap != null && imageView != null) {
mConfig.displayer.loadCompletedisplay(imageView, bitmap,
displayConfig);
} else if (bitmap == null && imageView != null) {
mConfig.displayer.loadFailDisplay(imageView,
displayConfig.getLoadfailBitmap());
}
}
@Override
protected void onCancelled(Bitmap bitmap) {
super.onCancelled(bitmap);
synchronized (mPauseWorkLock) {
mPauseWorkLock.notifyAll();
}
}
/**
* 获取线程匹配的imageView,防止出现闪动的现象
*
* @return
*/
private View getAttachedImageView() {
final View imageView = imageViewReference.get();
final BitmapLoadAndDisplayTask bitmapWorkerTask = getBitmapTaskFromImageView(imageView);
if (this == bitmapWorkerTask) {
return imageView;
}
return null;
}
}
/**
* @title 配置信息
* @description TvBitmap的配置信息
* @version 1.0
*/
private class TvBitmapConfig {
public String cachePath;
public Displayer displayer;
public Downloader downloader;
public BitmapDisplayConfig defaultDisplayConfig;
public float memCacheSizePercent;// 缓存百分比,android系统分配给每个apk内存的大小
public int memCacheSize;// 内存缓存百分比
public int diskCacheSize;// 磁盘百分比
public int poolSize = 3;// 默认的线程池线程并发数量
public boolean recycleImmediately = true;// 是否立即回收内存
public TvBitmapConfig(Context context) {
defaultDisplayConfig = new BitmapDisplayConfig(context);
defaultDisplayConfig.setAnimation(null);
defaultDisplayConfig
.setAnimationType(BitmapDisplayConfig.AnimationType.fadeIn);
// 设置图片的显示最大尺寸(为屏幕的大小,默认为屏幕宽度的1/2)
DisplayMetrics displayMetrics = context.getResources()
.getDisplayMetrics();
int defaultWidth = (int) Math.floor(displayMetrics.widthPixels / 2);
defaultDisplayConfig.setBitmapHeight(defaultWidth);
defaultDisplayConfig.setBitmapWidth(defaultWidth);
}
}
}