1 package com.bumptech.glide.load.engine; 2 3 import android.os.Looper; 4 5 import com.bumptech.glide.load.Key; 6 7 /** 8 * A wrapper resource that allows reference counting a wrapped {@link com.bumptech.glide.load.engine.Resource} 9 * interface. 10 * 11 * @param <Z> The type of data returned by the wrapped {@link Resource}. 12 */ 13 class EngineResource<Z> implements Resource<Z> { 14 private final Resource<Z> resource; 15 private final boolean isCacheable; 16 private ResourceListener listener; 17 private Key key; 18 private int acquired; 19 private boolean isRecycled; 20 21 interface ResourceListener { onResourceReleased(Key key, EngineResource<?> resource)22 void onResourceReleased(Key key, EngineResource<?> resource); 23 } 24 EngineResource(Resource<Z> toWrap, boolean isCacheable)25 EngineResource(Resource<Z> toWrap, boolean isCacheable) { 26 if (toWrap == null) { 27 throw new NullPointerException("Wrapped resource must not be null"); 28 } 29 resource = toWrap; 30 this.isCacheable = isCacheable; 31 } 32 setResourceListener(Key key, ResourceListener listener)33 void setResourceListener(Key key, ResourceListener listener) { 34 this.key = key; 35 this.listener = listener; 36 } 37 isCacheable()38 boolean isCacheable() { 39 return isCacheable; 40 } 41 42 @Override get()43 public Z get() { 44 return resource.get(); 45 } 46 47 @Override getSize()48 public int getSize() { 49 return resource.getSize(); 50 } 51 52 @Override recycle()53 public void recycle() { 54 if (acquired > 0) { 55 throw new IllegalStateException("Cannot recycle a resource while it is still acquired"); 56 } 57 if (isRecycled) { 58 throw new IllegalStateException("Cannot recycle a resource that has already been recycled"); 59 } 60 isRecycled = true; 61 resource.recycle(); 62 } 63 64 /** 65 * Increments the number of consumers using the wrapped resource. Must be called on the main thread. 66 * 67 * <p> 68 * This must be called with a number corresponding to the number of new consumers each time new consumers 69 * begin using the wrapped resource. It is always safer to call acquire more often than necessary. Generally 70 * external users should never call this method, the framework will take care of this for you. 71 * </p> 72 */ acquire()73 void acquire() { 74 if (isRecycled) { 75 throw new IllegalStateException("Cannot acquire a recycled resource"); 76 } 77 if (!Looper.getMainLooper().equals(Looper.myLooper())) { 78 throw new IllegalThreadStateException("Must call acquire on the main thread"); 79 } 80 ++acquired; 81 } 82 83 /** 84 * Decrements the number of consumers using the wrapped resource. Must be called on the main thread. 85 * 86 * <p> 87 * This must only be called when a consumer that called the {@link #acquire()} method is now done with the 88 * resource. Generally external users should never callthis method, the framework will take care of this for 89 * you. 90 * </p> 91 */ release()92 void release() { 93 if (acquired <= 0) { 94 throw new IllegalStateException("Cannot release a recycled or not yet acquired resource"); 95 } 96 if (!Looper.getMainLooper().equals(Looper.myLooper())) { 97 throw new IllegalThreadStateException("Must call release on the main thread"); 98 } 99 if (--acquired == 0) { 100 listener.onResourceReleased(key, this); 101 } 102 } 103 } 104