1.BitmapFactory
一.Glide手写实现之资源封装
资源封装
Key -- 对Value的唯一性进行描述
Value -- Bitmap的封装(+1, -1, 释放)
1.1代码
/**
* 唯一的描述
*/
public class Key {
private String key; // 例如:ac037ea49e34257dc5577d1796bb137dbaddc0e42a9dff051beee8ea457a4668
/**
* 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);
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
}
/**
* 对Bitmap的封装
*/
public class Value {
private final String TAG = Value.class.getSimpleName();
private Value() {}
// 单利模式
private static Value value;
public static Value getInstance() {
if (null == value) {
synchronized (Value.class) {
if (null == value) {
value = new Value();
}
}
}
return value;
}
private Bitmap mBitmap;
// 使用计数
private int count;
// 监听
private ValueCallback callback;
// 定义key
private String key;
public Bitmap getmBitmap() {
return mBitmap;
}
public void setmBitmap(Bitmap mBitmap) {
this.mBitmap = mBitmap;
Log.d(TAG, "setmBitmap: VVVVVVVV setBitmap:" + mBitmap.isMutable());
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public ValueCallback getCallback() {
return callback;
}
public void setCallback(ValueCallback callback) {
this.callback = callback;
}
public String getKey() {
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() {
count--;
if (count <= 0 && callback != null) {
// 回调告诉外界,不再使用了
Log.d(TAG, "nonUseAction: VVVVVV mBitmap.isMutable():" + mBitmap.isMutable());
callback.valueNonUseListener(key, value);
}
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();
}
}
/**
* 专门给Value,不再使用了,的回调接口
*/
public interface ValueCallback {
/**
* 监听的方法(Value不再使用了)
* @param key
* @param value
*/
public void valueNonUseListener(String key, Value value);
}
二.Glide手写实现之活动缓存
2.1回收机制:GC扫描的时候回收,移除容器(GC被动移除)(弱引用)
2.2容器管理方式:资源的封装 Key ----- (弱引用<Value>)
2.3手动移除的区分
2.4关闭线程
2.5Value监听加入
2.1 代码
/**
* 活动缓存 -- 真正被使用的资源
*/
public class ActiveCache {
// 容器
private Map<String, CustomoWeakReference> mapList = new HashMap<>();
private Map<String, Bitmap> mapValueList = new HashMap<>();
private ReferenceQueue<Value> queue; // 目的:为了监听这个弱引用 是否被回收了
private boolean isCloseThread;
private Thread thread;
private boolean isShoudonRemove;
private ValueCallback valueCallback;
public ActiveCache(ValueCallback valueCallback) {
this.valueCallback = valueCallback;
}
/**
* TODO 添加 活动缓存
* @param key
* @param value
*/
public void put(String key, Value value) {
Tool.checkNotEmpty(key);
// 没有问题
// Log.d("activeCache", "put: Inputkey:" + key + " --- value:" + value.getmBitmap() + "对应 key:" + value.getKey());
// 绑定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 Value get(String key) {
CustomoWeakReference valueWeakReference = mapList.get(key);
// Log.d("activeCache", "get: 自定义的弱引用" + valueWeakReference); // 不一样的
if (null != valueWeakReference) {
Value value = valueWeakReference.getValue(); // 返回Value
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 Value remove(String key) {
isShoudonRemove = true;
WeakReference<Value> valueWeakReference = mapList.remove(key);
isShoudonRemove = false; // 还原 目的是为了 让 GC自动移除 继续工作
if (null != valueWeakReference) {
return valueWeakReference.get();
}
return null;
}
/**
* TODO 释放 关闭线程
*/
public void closeThread() {
isCloseThread = true;
/*if (null != thread) {
thread.interrupt(); // 中断线程
try {
thread.join(TimeUnit.SECONDS.toMillis(5)); // 线程稳定安全 停止下来
if (thread.isAlive()) { // 证明线程还是没有结束
throw new IllegalStateException("活动缓存中 关闭线程 线程没有停止下来...");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}*/
mapList.clear();
System.gc();
}
/**
* 监听弱引用 成为弱引用的子类 为什么要成为弱引用的子类(目的:为了监听这个弱引用 是否被回收了)
*/
public static final class CustomoWeakReference extends WeakReference<Value> {
private String key;
private Value value;
public CustomoWeakReference(Value value, ReferenceQueue<? super Value> queue, String key) {
super(value, queue);
this.key = key;
this.value = value;
// Log.d("activeCache", "构造 put: Inputkey:" + key + " --- value:" + this.value.getmBitmap() + "对应 key:" + this.value.getKey());
}
public Value getValue() {
return this.value;
}
}
/**
* 为了监听 弱引用被回收,被动移除的
* @return
*/
private ReferenceQueue<Value> getQueue() {
if (queue == null) {
queue = new ReferenceQueue<>();
// 监听这个弱引用 是否被回收了
thread = new Thread(){
@Override
public void run() {
super.run();
while (!isCloseThread) {
try {
if (!isShoudonRemove) {
// queue.remove(); 阻塞式的方法
Reference<? extends Value> remove = queue.remove(); // 如果已经被回收了,就会执行到这个方法
CustomoWeakReference weakReference = (CustomoWeakReference) remove;
// 移除容器 !isShoudonRemove:为了区分手动移除 和 被动移除
if (mapList != null && !mapList.isEmpty() && !mapValueList.isEmpty()) {
mapList.remove(weakReference.key);
mapValueList.remove(weakReference.key);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
thread.start();
}
return queue;
}
}
三.Glide手写实现之内存缓存(LRU算法)
LRU算法:最近没有使用的元素,会自动被移除掉
职责:
活动缓存:给正在使用的资源存储的,弱引用
内存缓存:为第二次缓存服务,LRU算法
LRU算法: ---> 最近没有使用的元素,会自动被移除掉
把最近没有使用到的元素给移除
LruCache v4:
利用LinkedHashMap<K, V>,
LinkedHashMap: true==拥有访问排序的功能 (最少使用元素算法-LRU算法)
3.1.lru算法 图示
image.png3.2内存缓存 代码
public class MemoryCache extends LruCache<String, Value> {
MemoryCacheCallBack memoryCacheCallBack;
private boolean shoudongRemove;
public MemoryCacheCallBack getMemoryCacheCallBack() {
return memoryCacheCallBack;
}
public void setMemoryCacheCallBack(MemoryCacheCallBack memoryCacheCallBack) {
this.memoryCacheCallBack = memoryCacheCallBack;
}
public void shoudongRemove(String key) {
shoudongRemove = true;
remove(key);
shoudongRemove = false;
}
/**
* 传入最大值
*/
public MemoryCache(int maxSize) {
super(maxSize);
}
/**
* 存储的 键值对 key
* @param key
* @param value
* @return
*/
@Override
protected int sizeOf(String key, Value value) {
Bitmap bitmap = value.getBitmap();
int sdkInt = Build.VERSION.SDK_INT;
if (sdkInt >= Build.VERSION_CODES.KITKAT) {
return bitmap.getAllocationByteCount();
}
return bitmap.getByteCount();
}
/**
* lru 删除的回调
* @param evicted
* @param key
* @param oldValue
* @param newValue
*/
@Override
protected void entryRemoved(boolean evicted, String key, Value oldValue, Value newValue) {
super.entryRemoved(evicted, key, oldValue, newValue);
if (memoryCacheCallBack != null && !shoudongRemove) {
memoryCacheCallBack.entryRemoveMemoryCache(key,oldValue);
}
}
}
四 Glide手写实现之磁盘缓存
保存时长比较长:保存在本地磁盘 文件的形式存储 (不再是保存在运行内存中,而是磁盘中)
LRU算法: ---> 最近没有使用的元素,会自动被移除掉
DiskLruCache --- Android中没有提供了 --> DiskLruCache
DiskLruCache:回收方式:LRU算法, 访问排序 面向磁盘文件保存
4.1 图示
image.png4.2 磁盘存储代码 主要用到了第三方的 DiskLruCache 类 写到 put 和 get 方法
/**
* 磁盘 存储
*/
public class DiskLruCacheImpl {
private final String Tag = this.getClass().getSimpleName();
private DiskLruCache diskLruCache;
private final String File_Url = Environment.getExternalStorageState() + File.separator + "cain_disk_cache";
private final int appVersion = 1;
private final int valueCount = 1;
private final long maxSize = 1024 * 1024 * 10;
public DiskLruCacheImpl() {
try {
File file = new File(File_Url);
diskLruCache = DiskLruCache.open(file,appVersion,valueCount,maxSize);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 存入数据 写入 磁盘中
* @param key
* @param value
*/
public void put(String key, Value value) {
OutputStream outputStream = null;
DiskLruCache.Editor edit = null;
try {
edit = diskLruCache.edit(key);
outputStream = edit.newOutputStream(0);
Bitmap bitmap = value.getBitmap();
bitmap.compress(Bitmap.CompressFormat.PNG,100,outputStream);
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
try {
edit.abort();
} catch (IOException ex) {
ex.printStackTrace();
Log.e(Tag,"put:edit.abort() e:" + e.getMessage());
}
}finally {
try {
edit.commit();
} catch (IOException e) {
e.printStackTrace();
Log.e(Tag,"put:edit.commit() e:" + e.getMessage());
}
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
Log.e(Tag,"put:outputStream.close() e:" + e.getMessage());
}
}
}
/**
* 取数据 从磁盘中取数据
* @param key
* @return
*/
public Value get(String key) {
Tool.checkNotEmpty(key);
InputStream inputStream = null;
try {
Value value = Value.getInstance();
DiskLruCache.Snapshot snapshot = diskLruCache.get(key);
inputStream = snapshot.getInputStream(0);
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
value.setBitmap(bitmap);
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 --> V4包 Fragment
为什么发送一次Handler?
我们的Android基于Handler消息的,LAUNCH_ACTIVITY,为了让我们的fragment,不要再排队中,为了下次可以取出来
移除Handler
5.1 主要代码
public class RequestManager {
private final String Fragment_Activity_NAME = "Fragment_Activity_NAME";
private final String Activity_NAME = "Activity_NAME";
private final int NEXT_HANDLE_MSG = 99545;
private Context requestManagerContext;
private RequestTargetEngine requestTargetEngine;
{
if (requestTargetEngine == null) {
requestTargetEngine = new RequestTargetEngine();
}
}
public RequestManager(Activity mainActivity) {
this.requestManagerContext = mainActivity;
android.app.FragmentManager fragmentManager = mainActivity.getFragmentManager();
android.app.Fragment fragmentByTag = fragmentManager.findFragmentByTag(Activity_NAME);
if (fragmentByTag == null ) {
fragmentByTag = new ActivityFragmentManager(requestTargetEngine);
fragmentManager.beginTransaction().add(fragmentByTag,Activity_NAME).commitAllowingStateLoss();
}
myHandler.sendEmptyMessage(NEXT_HANDLE_MSG);
}
public RequestManager(FragmentActivity mainActivity) {
this.requestManagerContext = mainActivity;
FragmentManager supportFragmentManager = mainActivity.getSupportFragmentManager();
Fragment fragmentByTag = supportFragmentManager.findFragmentByTag(Fragment_Activity_NAME);
if (fragmentByTag == null) {
fragmentByTag = new FragmentActivityFragmentManager(requestTargetEngine);
supportFragmentManager.beginTransaction().add(fragmentByTag,Fragment_Activity_NAME).commitAllowingStateLoss();
}
myHandler.sendEmptyMessage(NEXT_HANDLE_MSG);
}
private Handler myHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message message) {
return false;
}
});
public RequestManager(Context mainActivity) {
this.requestManagerContext = mainActivity;
}
public RequestTargetEngine load(String path) {
requestTargetEngine.loadValueInitAction(path,requestManagerContext);
return requestTargetEngine;
}
}
5.2
public class Glide {
private RequestManagerRetriever requestManagerRetriever;
public Glide(RequestManagerRetriever requestManagerRetriever) {
this.requestManagerRetriever = requestManagerRetriever;
}
public static RequestManager with(Activity mainActivity) {
return getRetriever(mainActivity).get(mainActivity);
}
public static RequestManager with(FragmentActivity mainActivity) {
return getRetriever(mainActivity).get(mainActivity);
}
public static RequestManager with(Context mainActivity) {
return getRetriever(mainActivity).get(mainActivity);
}
public static RequestManagerRetriever getRetriever(Context context) {
return Glide.get(context).getRequestManagerRetriever();
}
/**
* glide 是 new 出来的转变
* @param context
* @return
*/
public static Glide get(Context context) {
return new GlideBuild().build();
}
public RequestManagerRetriever getRequestManagerRetriever() {
return requestManagerRetriever;
}
public void setRequestManagerRetriever(RequestManagerRetriever requestManagerRetriever) {
this.requestManagerRetriever = requestManagerRetriever;
}
}
六 Glide手写实现之加载图片
组拼接之前的所有内容(缓存) --> Glide
加载资源 --》 缓存 ---》网络/SD/ 加载资源 成功后 --》资源 保存到缓存中
总结:
第一次的时候,去网络下载图片,保存到磁盘缓存中(/sd/disk_lru_cache_dir/key)
第二次的时候,直接再活动缓存中,找到了资源
第三次的时候,直接再活动缓存中,找到了资源
第N次的时候,直接再活动缓存中,找到了资源
把Activity给返回回去的时候,进行释放,活动缓存的释放
又一次加载的时候,从内存缓存中获取了
下一次加载的时候,就是从活动缓存获取了
把App给杀掉
整个活动缓存,整个内存缓存,都没有了
所以从磁盘缓存中获取
网友评论