package com.bumptech.glide.load.engine;
import android.os.Looper;
import com.bumptech.glide.load.Key;
import com.bumptech.glide.util.Preconditions;
/**
* A wrapper resource that allows reference counting a wrapped {@link
* com.bumptech.glide.load.engine.Resource} interface.
*
* @param <Z> The type of data returned by the wrapped {@link Resource}.
*/
class EngineResource<Z> implements Resource<Z> {
private final boolean isCacheable;
private ResourceListener listener;
private Key key;
private int acquired;
private boolean isRecycled;
private final Resource<Z> resource;
interface ResourceListener {
void onResourceReleased(Key key, EngineResource<?> resource);
}
EngineResource(Resource<Z> toWrap, boolean isCacheable) {
resource = Preconditions.checkNotNull(toWrap);
this.isCacheable = isCacheable;
}
void setResourceListener(Key key, ResourceListener listener) {
this.key = key;
this.listener = listener;
}
boolean isCacheable() {
return isCacheable;
}
@Override
public Class<Z> getResourceClass() {
return resource.getResourceClass();
}
@Override
public Z get() {
return resource.get();
}
@Override
public int getSize() {
return resource.getSize();
}
@Override
public void recycle() {
if (acquired > 0) {
throw new IllegalStateException("Cannot recycle a resource while it is still acquired");
}
if (isRecycled) {
throw new IllegalStateException("Cannot recycle a resource that has already been recycled");
}
isRecycled = true;
resource.recycle();
}
/**
* Increments the number of consumers using the wrapped resource. Must be called on the main
* thread.
*
* <p> This must be called with a number corresponding to the number of new consumers each time
* new consumers begin using the wrapped resource. It is always safer to call acquire more often
* than necessary. Generally external users should never call this method, the framework will take
* care of this for you. </p>
*/
void acquire() {
if (isRecycled) {
throw new IllegalStateException("Cannot acquire a recycled resource");
}
if (!Looper.getMainLooper().equals(Looper.myLooper())) {
throw new IllegalThreadStateException("Must call acquire on the main thread");
}
++acquired;
}
/**
* Decrements the number of consumers using the wrapped resource. Must be called on the main
* thread.
*
* <p> This must only be called when a consumer that called the {@link #acquire()} method is now
* done with the resource. Generally external users should never callthis method, the framework
* will take care of this for you. </p>
*/
void release() {
if (acquired <= 0) {
throw new IllegalStateException("Cannot release a recycled or not yet acquired resource");
}
if (!Looper.getMainLooper().equals(Looper.myLooper())) {
throw new IllegalThreadStateException("Must call release on the main thread");
}
if (--acquired == 0) {
listener.onResourceReleased(key, this);
}
}
@Override
public String toString() {
return "EngineResource{"
+ "isCacheable=" + isCacheable
+ ", listener=" + listener
+ ", key=" + key
+ ", acquired=" + acquired
+ ", isRecycled=" + isRecycled
+ ", resource=" + resource
+ '}';
}
}