Restored enforced synchronization on BitmapRegionDecoder for SDK < 21, which did not have internal synchronization
diff --git a/library/src/main/java/com/davemorrissey/labs/subscaleview/decoder/SkiaImageRegionDecoder.java b/library/src/main/java/com/davemorrissey/labs/subscaleview/decoder/SkiaImageRegionDecoder.java
index 9d216f6..28f5d80 100644
--- a/library/src/main/java/com/davemorrissey/labs/subscaleview/decoder/SkiaImageRegionDecoder.java
+++ b/library/src/main/java/com/davemorrissey/labs/subscaleview/decoder/SkiaImageRegionDecoder.java
@@ -7,10 +7,12 @@
import android.content.res.Resources;
import android.graphics.*;
import android.net.Uri;
+import android.os.Build;
import android.text.TextUtils;
import java.io.InputStream;
import java.util.List;
+import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -21,9 +23,9 @@
* however it has some problems with grayscale, indexed and CMYK images.
*
* A {@link ReadWriteLock} is used to delegate responsibility for multi threading behaviour to the
- * {@link BitmapRegionDecoder} instance, whilst allowing this class to block until no tiles are being
- * loaded before recycling the decoder. In practice, {@link BitmapRegionDecoder} is single threaded
- * so this has no real impact on performance.
+ * {@link BitmapRegionDecoder} instance on SDK >= 21, whilst allowing this class to block until no
+ * tiles are being loaded before recycling the decoder. In practice, {@link BitmapRegionDecoder} is
+ * synchronized internally so this has no real impact on performance.
*/
public class SkiaImageRegionDecoder implements ImageRegionDecoder {
@@ -97,7 +99,7 @@
@Override
public Bitmap decodeRegion(Rect sRect, int sampleSize) {
- decoderLock.readLock().lock();
+ getDecodeLock().lock();
try {
if (decoder != null && !decoder.isRecycled()) {
BitmapFactory.Options options = new BitmapFactory.Options();
@@ -112,27 +114,36 @@
throw new IllegalStateException("Cannot decode region after decoder has been recycled");
}
} finally {
- decoderLock.readLock().unlock();
+ getDecodeLock().unlock();
}
}
@Override
- public boolean isReady() {
- decoderLock.readLock().lock();
- try {
- return decoder != null && !decoder.isRecycled();
- } finally {
- decoderLock.readLock().unlock();
- }
+ public synchronized boolean isReady() {
+ return decoder != null && !decoder.isRecycled();
}
@Override
- public void recycle() {
+ public synchronized void recycle() {
decoderLock.writeLock().lock();
try {
decoder.recycle();
+ decoder = null;
} finally {
decoderLock.writeLock().unlock();
}
}
+
+ /**
+ * Before SDK 21, BitmapRegionDecoder was not synchronized internally. Any attempt to decode
+ * regions from multiple threads with one decoder instance causes a segfault. For old versions
+ * use the write lock to enforce single threaded decoding.
+ */
+ private Lock getDecodeLock() {
+ if (Build.VERSION.SDK_INT < 21) {
+ return decoderLock.writeLock();
+ } else {
+ return decoderLock.readLock();
+ }
+ }
}