Glide 资源封装
key --对value的唯一性进行描述
value --对bitmap的封装(+1 -1 释放)
public class Glide {
RequestManagerRetriverretriver;
public Glide(RequestManagerRetriver retriver) {
this.retriver = retriver;
}
public static RequestManagerwith(FragmentActivity fragmentActivity) {
return getRetriever(fragmentActivity).get(fragmentActivity);
}
public static RequestManagerwith(Activity activity) {
return getRetriever(activity).get(activity);
}
private static RequestManagerwith(Context context) {
return getRetriever(context).get(context);
}
/**
* RequestManager有我们的RequestManagerRetriver去创建的
* @return
*/
public static RequestManagerRetrivergetRetriever(Context context){
return Glide.get(context).getRetriver();
}
// Glide 是 new出来的 -- 转变
public static Glideget(Context context) {
return new GlideBuilder().build();
}
/**
* RequestManagerRetriver
* @return
*/
public RequestManagerRetrivergetRetriver() {
return retriver;
}
public class RequestManagerRetriver {
public RequestManagerget(FragmentActivity fragmentActivity){
return new RequestManager(fragmentActivity);
}
public RequestManagerget(Activity activity){
return new RequestManager(activity);
}
public RequestManagerget(Context context){
return new RequestManager(context);
}
}
/**
* 创建Glide
* @return
*/
public Glidebuild() {
RequestManagerRetriver requestManagerRetriver =new RequestManagerRetriver();
Glide glide =new Glide(requestManagerRetriver);
return glide;
}
}
/**
* 唯一的描述
*/
public class Key {
private Stringkey; // 例如:ac037ea49e34257dc5577d1796bb137dbaddc0e42a9dff051beee8ea457a4668
public StringgetKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
/**
* sha256(https://cn.bing.com/sa/simg/hpb/LaDigue_EN-CA1115245085_1920x1080.jpg)之前
* ac037ea49e34257dc5577d1796bb137dbaddc0e42a9dff051beee8ea457a4668 处理后
* @param key
*/
public Key(String key) {
//this.key = key;
this.key = Tool.getSHA256StrJava(key);
}
}
/**
* 对Bitmap的封装
*/
public class Value {
private final StringTAG = Value.class.getSimpleName();
// 单利模式
private static Valuevalue;
public static ValuegetInstance() {
if (null ==value) {
synchronized (Value.class) {
if (null ==value) {
value =new Value();
}
}
}
return value;
}
private BitmapmBitmap;
// 使用计数
private int count;
// 监听
private ValueCallbackcallback;
// 定义key
private Stringkey;
public BitmapgetmBitmap() {
return mBitmap;
}
public void setmBitmap(Bitmap mBitmap) {
this.mBitmap = mBitmap;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public ValueCallbackgetCallback() {
return callback;
}
public void setCallback(ValueCallback callback) {
this.callback = callback;
}
public StringgetKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
/**
* TODO 使用一次 就 加一
*/
public void useAction() {
Tool.checkNotEmpty(mBitmap);
if (mBitmap.isRecycled()) {// 已经被回收了
Log.d(TAG, "useAction: 已经被回收了");
return;
}
Log.d(TAG, "useAction: 加一 count:" +count);
count ++;
}
/**
* TODO 使用完成(不使用) 就 减一
* count -- <= 0 不再使用了
*/
public void nonUseAction() {
if (count -- <=0 &&callback !=null) {
// 回调告诉外界,不再使用了
callback.valueNonUseListener(key, this);
}
Log.d(TAG, "useAction: 减一 count:" +count);
}
/**
* TODO 释放
*/
public void recycleBitmap() {
if (count >0) {
Log.d(TAG, "recycleBitmap: 引用计数大于0,证明还在使用中,不能去释放...");
return;
}
if (mBitmap.isRecycled()) {// 被回收了
Log.d(TAG, "recycleBitmap: mBitmap.isRecycled() 已经被释放了...");
return;
}
mBitmap.recycle();
value =null;
System.gc();
}
}
public interface ValueCallback {
/**
* 监听的方法(Value不再使用了)
* @param key
* @param value
*/
public void valueNonUseListener(String key, Value value);
}
Glide 活动缓存
回收机制:GC扫描的时候回收,移除容器(GC被动移除)弱引用
容器管理方式:资源的封装key,(弱引用
手动移除的区分(手动移除map还是GC移除)
关闭线程
value监听加入
/**
* 活动缓存 -- 真正被使用的资源
*/
public class ActiveCache {
// 容器
private MapmapList=new HashMap<>();
private MapmapValueList=new HashMap<>();
private ReferenceQueuequeue;//目的:为了监听这个弱引用是否被回收了
private boolean isClosedThread;
private Threadthread;
private boolean isShoudongRemove;
private ValueCallbackvalueCallback;
public ActiveCache(ValueCallback valueCallback){
this.valueCallback=valueCallback;
}
/**
* TODO 添加 活动缓存
* @param key
* @param value
*/
public void put(String key,Value value){
Tool.checkNotEmpty(key);
// 绑定Value的监听 --> Value发起来的(Value没有被使用了,就会发起这个监听,给外界业务需要来使用)
value.setCallback(valueCallback);
//存储
mapList.put(key,new CustomoWeakReference(value,getQueue(),key));
mapValueList.put(key,value.getmBitmap());
}
/**
* TODO 给外界获取Value
* @param key
* @return
*/
public Valueget(String key){
CustomoWeakReference valueWeakReference=mapList.get(key);
if(null!=valueWeakReference){
Value value=valueWeakReference.getValue();
value.setmBitmap(mapValueList.get(key));
value.setKey(key);
// bug每次 value信息一致
Log.d("activeCache", "get: Inputkey:" + key +" --- value:" + value.getmBitmap() +"对应 key:" + value.getKey());
return value;
}
return null;
}
/**
* TODO 手动移除
* @param key
* @return
*/
public Valueremove(String key){
isShoudongRemove=true;
WeakReference valueWeakReference=mapList.remove(key);
isShoudongRemove=false;
if(null!=valueWeakReference){
return valueWeakReference.get();
}
return null;
}
/**
* TODO 释放 关闭线程
*/
public void closeThread(){
isClosedThread=true;
mapValueList.clear();
System.gc();
}
/**
* 监听弱引用 成为弱引用的子类 为什么要成为弱引用的子类(目的:为了监听这个弱引用 是否被回收了)
*/
class CustomoWeakReferenceextends WeakReference{
private Stringkey;
private Valuevalue;
public CustomoWeakReference(Value value, ReferenceQueue queue,String key) {
super(value, queue);
this.key=key;
this.value=value;
}
public ValuegetValue(){
return this.value;
}
/**
* 为了监听 弱引用被回收,被动移除的
* @return
*/
}
public ReferenceQueuegetQueue(){
if(queue==null){
queue=new ReferenceQueue<>();
// 监听这个弱引用 是否被回收了
thread=new Thread(){
@Override
public void run() {
super.run();
while (!isClosedThread) {
if(!isShoudongRemove){
// queue.remove(); 阻塞式的方法
try {
Reference remove=queue.remove();// 如果已经被回收了,就会执行到这个方法
CustomoWeakReference weakReference=(CustomoWeakReference) remove;
// 移除容器 !isShoudonRemove:为了区分手动移除 和 被动移除
if(mapList!=null&&!mapList.isEmpty()&&!mapValueList.isEmpty()){
mapList.remove(weakReference.key);
mapValueList.remove(weakReference.key);
}
}catch (Exception e) {
e.printStackTrace();
}
}
}
}
};
thread.start();
}
return queue;
}
}
Glide 内存缓存
LRU算法:最近没有使用的元素,会自动被移除掉
职责:
活动缓存:给正在使用的资源存储的,弱引用
内存缓存:为第二次缓存服务,LRU算法
LRU算法: ---> 最近没有使用的元素,会自动被移除掉
把最近没有使用到的元素给移除
LruCache v4:
利用LinkedHashMap
LinkedHashMap: true==拥有访问排序的功能 (最少使用元素算法-LRU算法)
put:
1.如果是重复的key,会被移除掉一个
key=15151511551
previous = key=15151511551
entryRemoved
2.trimToSize 移除哪些最近没有使用的元素 ---》 entryRemoved
public class MemoryCacheextends LruCache {
private boolean shouDonRemove;
//TODO 手动移除
public ValueshouDonRemove(String key){
shouDonRemove=true;
Value value=remove(key);
shouDonRemove=false; // !shoudonRemove == 被动的
return value;
}
private MemoryCacheCallbackmemoryCacheCallback;
public void setMemoryCacheCallback(MemoryCacheCallback memoryCacheCallback){
this.memoryCacheCallback=memoryCacheCallback;
}
/**
* 传入元素最大值,给LruCache
* @param maxSize
*/
/**
* @param maxSize for caches that do not override {@link #sizeOf}, this is
* the maximum number of entries in the cache. For all other caches,
* this is the maximum sum of the sizes of the entries in this cache.
*/
public MemoryCache(int maxSize) {
super(maxSize);
}
@Override
protected int sizeOf(@NonNull String key, @NonNull Value value) {
Bitmap bitmap=value.getmBitmap();
int sdkInt= Build.VERSION.SDK_INT;
if(sdkInt>=Build.VERSION_CODES.KITKAT){
return bitmap.getAllocationByteCount();
}
return bitmap.getByteCount();
}
/**
* 1.重复的key
* 2.最少使用的元素会被移除
* @param evicted
* @param key
* @param oldValue
* @param newValue
*/
@Override
protected void entryRemoved(boolean evicted, @NonNull String key, @NonNull Value oldValue, @Nullable Value newValue) {
super.entryRemoved(evicted, key, oldValue, newValue);
if(memoryCacheCallback!=null&&!shouDonRemove){
memoryCacheCallback.entryRemovedMemoryCache(key,oldValue);
}
}
}
/**
* 内存缓存中,元素被移除的接口回调
*/
/**
* 内存缓存中移除的 key--value
* @param key
* @param oldValue
*/
public void entryRemovedMemoryCache(String key, Value oldValue);
}
Glide 磁盘缓存
保存时间比较长,保存在本地磁盘,文件的形式存储,(不再是保存在内存中,而是磁盘中)
Lru算法:最近没有使用的会被优先自动移除掉
LruCache : Android中的v4;
LruCache :访问排序。底层利用lickedMap集合实现
引用JakeWharton大神的DiskLruCache
/**
* 磁盘缓存的封装
*/
public class DiskLruCacheImpl {
private final StringTAG = DiskLruCacheImpl.class.getSimpleName();
// SD/disk_lru_cache_dir/ac037ea49e34257dc5577d1796bb137dbaddc0e42a9dff051beee8ea457a4668
private final StringDISKLRU_CACHE_DIR ="disk_lru_cache_dir"; // 磁盘缓存的的目录
private final int APP_VERSION =1; // 我们的版本号,一旦修改这个版本号,之前的缓存失效
private final int VALUE_COUNT =1; // 通常情况下都是1
private final long MAX_SIZE =1024 *1024 *100; // 以后修改成 使用者可以设置的 注意:可以自己去自动配置
private DiskLruCachediskLruCache;
public DiskLruCacheImpl() {
File file =new File(Environment.getExternalStorageDirectory() + File.separator +DISKLRU_CACHE_DIR);
try {
diskLruCache = DiskLruCache.open(file, APP_VERSION, VALUE_COUNT, MAX_SIZE);
}catch (IOException e) {
e.printStackTrace();
}
}
// TODO put
public void put(String key, Value value) {
Tool.checkNotEmpty(key);
DiskLruCache.Editor editor =null;
OutputStream outputStream =null;
try {
editor =diskLruCache.edit(key);
outputStream = editor.newOutputStream(0);// index 不能大于 VALUE_COUNT
Bitmap bitmap = value.getmBitmap();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream); // 把bitmap写入到outputStream
outputStream.flush();
}catch (IOException e) {
e.printStackTrace();
// 失败
try {
editor.abort();
}catch (IOException e1) {
e1.printStackTrace();
Log.e(TAG, "put: editor.abort() e:" + e.getMessage());
}
}finally {
try {
editor.commit(); // sp 记得一定要提交
diskLruCache.flush();
}catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "put: editor.commit(); e:" + e.getMessage());
}
if (outputStream !=null) {
try {
outputStream.close();
}catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "put: outputStream.close(); e:" + e.getMessage());
}
}
}
}
// TODO get
public Valueget(String key) {
Tool.checkNotEmpty(key);
InputStream inputStream =null;
try {
DiskLruCache.Snapshot snapshot =diskLruCache.get(key);
// 判断快照不为null的情况下,在去读取操作
if (null != snapshot) {
Value value = Value.getInstance();
inputStream = snapshot.getInputStream(0);// index 不能大于 VALUE_COUNT
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
value.setmBitmap(bitmap);
// 保存key 唯一标识
value.setKey(key);
return value;
}
}catch (IOException e) {
e.printStackTrace();
}finally {
if (null != inputStream) {
try {
inputStream.close();
}catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "get: inputStream.close(); e:" + e.getMessage());
}
}
}
return null; // 为了后续好判断
}
}
Glide 生命周期
组拼之前的所有所有内容---glide
生命周期的管理:application不能去管理,FragmentActivity和Activity可以去管理
管理的方式:在Activity的组件上,附件fragment,通过fragment的监听组件的生命周期
Activity---app fragment
AppCompatActivity---androidx包fragment
为什么发送一次handler?
我们的Android基于handler消息的,LAUNCH_ACTIVITY,为了让我们的fragment,不要在排队中,为了下次可以取出来移除Handler
public class ActivityFragmentManagerextends Fragment {
public ActivityFragmentManager(){}
private LifecycleCallbacklifecycleCallback;
@SuppressLint("ValidFragment")
public ActivityFragmentManager(LifecycleCallback lifecycleCallback) {
this.lifecycleCallback = lifecycleCallback;
}
@Override
public void onStart() {
super.onStart();
if(lifecycleCallback!=null){
lifecycleCallback.glideInitAction();
}
}
@Override
public void onStop() {
super.onStop();
if (lifecycleCallback !=null) {
lifecycleCallback.glideStopAction();
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (lifecycleCallback !=null) {
lifecycleCallback.glideRecycleAction();
}
}
}
public class FragmentActivityFragmentManagerextends Fragment {
public FragmentActivityFragmentManager(){}
private LifecycleCallbacklifecycleCallback;
public FragmentActivityFragmentManager(LifecycleCallback lifecycleCallback) {
this.lifecycleCallback = lifecycleCallback;
}
@Override
public void onStart() {
super.onStart();
if (lifecycleCallback !=null) {
lifecycleCallback.glideInitAction();
}
}
@Override
public void onStop() {
super.onStop();
if (lifecycleCallback !=null) {
lifecycleCallback.glideStopAction();
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (lifecycleCallback !=null) {
lifecycleCallback.glideRecycleAction();
}
}
}
public interface LifecycleCallback {
// 生命周期初始化了
public void glideInitAction();
// 生命周期 停止了
public void glideStopAction();
// 生命周期 释放 操作了
public void glideRecycleAction();
}
Glide 加载图片
组拼接之前的所有内容(缓存) --> Glide
加载资源 --》 缓存 ---》网络/SD/ 加载资源 成功后 --》资源 保存到缓存中
/**
* 加载外部资源 成功与失败的 回调
*/
public interface ResponseListener {
public void responseSuccess(Value value);
public void responseException(Exception e);
}
/**
* 加载外部资源 标准
*/
public interface ILoadData {
// 加载外部资源的行为
public ValueloadResource(String path, ResponseListener responseListener, Context context);
}
/**
* 加载图片资源
*/
public class RequestTargetEngineimplements LifecycleCallback, ValueCallback, MemoryCacheCallback, ResponseListener {
private final StringTAG = RequestTargetEngine.class.getSimpleName();
/**
* 内存缓存发出的
* LRU最少使用的元素会被移除
* @param key
* @param oldValue
*/
@Override
public void entryRemovedMemoryCache(String key, Value oldValue) {
// 添加到复用池 ...... ,空留的功能点
}
@Override
public void glideInitAction() {
Log.d(TAG, "glideInitAction: Glide生命周期之 已经开启了 初始化了....");
}
@Override
public void glideStopAction() {
Log.d(TAG, "glideInitAction: Glide生命周期之 已经停止中 ....");
}
@Override
public void glideRecycleAction() {
Log.d(TAG, "glideInitAction: Glide生命周期之 进行释放操作 缓存策略释放操作等 >>>>>> ....");
if (activeCache !=null) {
activeCache.closeThread(); // 把活动缓存给释放掉
}
}
private ActiveCacheactiveCache;// 活动缓存
private MemoryCachememoryCache;// 内存缓存
private DiskLruCacheImpldiskLruCache;// 磁盘缓存
private final int MEMORY_MAX_SIZE =1024 *1024 *60;
public RequestTargetEngine() {
if (activeCache ==null) {
activeCache =new ActiveCache(this);
}
if (memoryCache ==null) {
memoryCache =new MemoryCache(MEMORY_MAX_SIZE);
memoryCache.setMemoryCacheCallback(this);
}
diskLruCache =new DiskLruCacheImpl();
Log.e("DissswkLruCach","RequestTargetEngine");
}
private Stringpath;
private ContextglideContext;
private Stringkey; // ac037ea49e34257dc5577d1796bb137dbaddc0e42a9dff051beee8ea457a4668
private ImageViewimageView; // 显示的目标
/**
* RequestManager传递的值
*/
public void loadValueInitAction(String path, Context glideContext) {
this.path = path;
this.glideContext = glideContext;
key =new Key(path).getKey();
}
public void into(ImageView imageView) {
this.imageView = imageView;
Tool.checkNotEmpty(imageView);
Tool.assertMainThread();
// TODO 加载资源 --》 缓存 ---》网络/SD/ 加载资源 成功后 --》资源 保存到缓存中 >>>
Value value = cacheAction();
if (value !=null) {
// 使用完成了 减一
value.nonUseAction();
imageView.setImageBitmap(value.getmBitmap());
}
}
// TODO 加载资源 --》 缓存 ---》网络/SD/ 加载资源 成功后 --》资源 保存到缓存中 >>>
private ValuecacheAction() {
// TODO 第一步,判断活动缓存是否有资源,如果有资源 就返回, 否则就继续往下找
Value value =activeCache.get(key);
if (null != value) {
Log.d(TAG, "cacheAction: 本次加载是在(活动缓存)中获取的资源>>>");
// 返回 代表 使用了一次 Value
value.useAction();
return value;
}
// TODO 第二步,从内存缓存中去找,如果找到了,内存缓存中的元素 “移动” 到 活动缓存, 然后再返回
value =memoryCache.get(key);
if (null != value) {
// 移动操作
memoryCache.shouDonRemove(key); // 移除内存缓存
activeCache.put(key, value); // 把内存缓存中的元素 加入到活动缓存中
Log.d(TAG, "cacheAction: 本次加载是在(内存缓存)中获取的资源>>>");
// 返回 代表 使用了一次 Value
value.useAction(); // 使用了一次 加一
return value;
}
// TODO 第三步,从磁盘缓存中去找,如果找到了,把磁盘缓存中的元素 加入到 活动缓存中
value =diskLruCache.get(key);
if (null != value) {
// 把磁盘缓存中的元素 --> 加入到活动缓存中
activeCache.put(key, value);
// 把磁盘缓存中的元素 --> 加入到内存缓存中
// memoryCache.put(key, value);
Log.d(TAG, "cacheAction: 本次加载是在(磁盘缓存)中获取的资源>>>");
// 返回 代表 使用了一次 Value
value.useAction(); // 使用了一次 加一
return value;
}
// TODO 第四步,真正的去加载外部资源了, 去网络上加载/去SD本地上加载
value =new LoadDataManager().loadResource(path, this, glideContext);
if (value !=null)
return value;
return null;
}
// 加载外部资源成功
@Override
public void responseSuccess(Value value) {
if (null != value) {
saveCahce(key, value);
imageView.setImageBitmap(value.getmBitmap());
}
}
/**
* 保存到缓存中
* @param key
* @param value
*/
private void saveCahce(String key, Value value) {
Log.d(TAG, "saveCahce: >>>>>>>>>>>>>>>>>>>>>> 加载外部资源成功后,保存到缓存中 key:" + key +" value:" + value);
value.setKey(key);
if (diskLruCache !=null) {
diskLruCache.put(key, value); // 保存到磁盘缓存中
}
}
// 加载外部资源失败
@Override
public void responseException(Exception e) {
Log.d(TAG, "responseException: 加载外部资源失败 e:" + e.getMessage());
}
/**
* 活动缓存间接的调用Value所发出的
* 回调告诉外界,Value资源不再使用了
* 监听的方法(Value不再使用了)
* @param key
* @param value
*/
@Override
public void valueNonUseListener(String key, Value value) {
// 把活动缓存操作的Value资源 加入到 内存缓存
if (key !=null && value !=null) {
memoryCache.put(key, value);
}
}
}
public class LoadDataManagerimplements ILoadData, Runnable {
private final StringTAG = LoadDataManager.class.getSimpleName();
private Stringpath;
private ResponseListenerresponseListener;
private Contextcontext;
@Override
public ValueloadResource(String path, ResponseListener responseListener, Context context) {
this.path = path;
this.responseListener = responseListener;
this.context = context;
// 加载 网络图片/SD本地图片/..
Uri uri = Uri.parse(path);
// 网络图片
if ("HTTP".equalsIgnoreCase(uri.getScheme()) ||"HTTPS".equalsIgnoreCase(uri.getScheme())) {
new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new SynchronousQueue()).execute(this);
}
return null;
}
@Override
public void run() {
InputStream inputStream =null;
HttpURLConnection httpURLConnection =null;
try {
URL url =new URL(path);
URLConnection urlConnection = url.openConnection();
httpURLConnection = (HttpURLConnection) urlConnection;
httpURLConnection.setConnectTimeout(5000);
final int responseCode = httpURLConnection.getResponseCode();
if(HttpURLConnection.HTTP_OK==responseCode){
inputStream=httpURLConnection.getInputStream();
final Bitmap bitmap= BitmapFactory.decodeStream(inputStream);
//成功 切换主线程
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
Value value=Value.getInstance();
value.setmBitmap(bitmap);
// 回调成功
responseListener.responseSuccess(value);
}
});
}else {
//失败 切换主线程
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
responseListener.responseException(new IllegalStateException("请求失败 请求码:" +responseCode));
}
});
}
}catch (Exception e) {
e.printStackTrace();
}finally {
if(inputStream!=null){
try {
inputStream.close();
}catch (IOException e) {
e.printStackTrace();
Log.d(TAG, "run: 关闭 inputStream.close(); e:" + e.getMessage());
}
}
if(httpURLConnection!=null){
httpURLConnection.disconnect();
}
}
}
}
总结:
第一次的时候,去网络下载图片,保存到磁盘缓存中(/sd/disk_lru_cache_dir/key)
第二次的时候,直接再活动缓存中,找到了资源
第三次的时候,直接再活动缓存中,找到了资源
第N次的时候,直接再活动缓存中,找到了资源
把Activity给返回回去的时候,进行释放,活动缓存的释放
又一次加载的时候,从内存缓存中获取了
下一次加载的时候,就是从活动缓存获取了
把App给杀掉
整个活动缓存,整个内存缓存,都没有了
所以从磁盘缓存中获取
---
LRU:LRU小知识点
---
1.活动缓存,HashMap管理的,用到了弱引用去回收移除 ----> 活动缓存(Value没有被使用了)移除后 交给 内存缓存
2.内存缓存,内存缓存作为第二道防线,LRU算法的
3.磁盘缓存,缓存中最后一道防线,保存手机存储的,LRU算法的
4.什么周期的管理,Fragment