mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
Image cache won't work if FileSystem is in read-only mode. (#66)
ImageView will remove its bitmap when not in visual tree and apply it back once shown. ImageView add setUri method. ViewHelper added new method for API 21.
This commit is contained in:
@@ -142,6 +142,12 @@ public class Cache {
|
||||
return bitmapSize == 0 ? 1 : bitmapSize;
|
||||
}
|
||||
};
|
||||
} else {
|
||||
clearCache();
|
||||
if (mReusableBitmaps != null) {
|
||||
mReusableBitmaps.clear();
|
||||
mReusableBitmaps = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,6 +242,7 @@ public class Cache {
|
||||
Log.v(TAG, "Memory cache cleared");
|
||||
}
|
||||
}
|
||||
mMemoryCache = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -246,18 +253,6 @@ public class Cache {
|
||||
public boolean memoryCacheEnabled = DEFAULT_MEM_CACHE_ENABLED;
|
||||
public boolean diskCacheEnabled = DEFAULT_DISK_CACHE_ENABLED;
|
||||
|
||||
/**
|
||||
* Create a set of image cache parameters that can be provided to
|
||||
* {@link Cache#getInstance(CacheParams)}.
|
||||
*
|
||||
* @param context A context to use.
|
||||
* @param diskCacheDirectoryName A unique subdirectory name that will be appended to the
|
||||
* application cache directory. Usually "cache" or "images"
|
||||
* is sufficient.
|
||||
*/
|
||||
public CacheParams(Context context, String diskCacheDirectoryName) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the memory cache size based on a percentage of the max available VM memory.
|
||||
* Eg. setting percent to 0.2 would set the memory cache to one fifth of the available
|
||||
|
||||
@@ -23,11 +23,14 @@ import android.util.Log;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
@@ -47,14 +50,22 @@ public class Fetcher extends Resizer {
|
||||
private static final int DISK_CACHE_INDEX = 0;
|
||||
|
||||
private final String mPackageName;
|
||||
private static Fetcher instance;
|
||||
|
||||
public static Fetcher getInstance(Context context) {
|
||||
if (instance == null) {
|
||||
instance = new Fetcher(context);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize providing a target image width and height for the processing images.
|
||||
*
|
||||
* @param context
|
||||
*/
|
||||
public Fetcher(Context context) {
|
||||
private Fetcher(Context context) {
|
||||
super(context);
|
||||
mHttpCacheDir = Cache.getDiskCacheDir(context, HTTP_CACHE_DIR);
|
||||
mPackageName = context.getPackageName();
|
||||
@@ -184,9 +195,9 @@ public class Fetcher extends Resizer {
|
||||
fileDescriptor = fileInputStream.getFD();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "processBitmap - " + e);
|
||||
Log.e(TAG, "processHttp - " + e);
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(TAG, "processBitmap - " + e);
|
||||
Log.e(TAG, "processHttp - " + e);
|
||||
} finally {
|
||||
if (fileDescriptor == null && fileInputStream != null) {
|
||||
try {
|
||||
@@ -216,19 +227,17 @@ public class Fetcher extends Resizer {
|
||||
if (debuggable > 0) {
|
||||
Log.v(TAG, "processHttp - " + data);
|
||||
}
|
||||
final String key = Cache.hashKeyForDisk(data);
|
||||
FileOutputStream outputStream = null;
|
||||
|
||||
ByteArrayOutputStreamInternal outputStream = null;
|
||||
Bitmap bitmap = null;
|
||||
|
||||
try {
|
||||
outputStream = new FileOutputStream(key);
|
||||
outputStream = new ByteArrayOutputStreamInternal();
|
||||
if (downloadUrlToStream(data, outputStream)) {
|
||||
bitmap = decodeSampledBitmapFromDescriptor(outputStream.getFD(), decodeWidth, decodeHeight, getCache());
|
||||
bitmap = decodeSampledBitmapFromByteArray(outputStream.getBuffer(), decodeWidth, decodeHeight, getCache());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "processBitmap - " + e);
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(TAG, "processBitmap - " + e);
|
||||
Log.e(TAG, "processHttpNoCache - " + e);
|
||||
} finally {
|
||||
if (outputStream != null) {
|
||||
try {
|
||||
@@ -263,7 +272,7 @@ public class Fetcher extends Resizer {
|
||||
Log.v(TAG, "Missing Image with resourceID: " + stringData);
|
||||
}
|
||||
} else {
|
||||
if (useCache) {
|
||||
if (useCache && mHttpDiskCache != null) {
|
||||
return processHttp(stringData, decodeWidth, decodeHeight);
|
||||
} else {
|
||||
return processHttpNoCache(stringData, decodeWidth, decodeHeight);
|
||||
@@ -328,4 +337,10 @@ public class Fetcher extends Resizer {
|
||||
System.setProperty("http.keepAlive", "false");
|
||||
}
|
||||
}
|
||||
|
||||
private static class ByteArrayOutputStreamInternal extends ByteArrayOutputStream {
|
||||
public byte[] getBuffer() {
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.os.Build;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* A simple subclass of {@link Worker} that resize images given a target width
|
||||
@@ -149,6 +150,34 @@ public abstract class Resizer extends Worker {
|
||||
return BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
|
||||
}
|
||||
|
||||
public static Bitmap decodeSampledBitmapFromByteArray(
|
||||
byte[] buffer, int reqWidth, int reqHeight, Cache cache) {
|
||||
|
||||
// First decode with inJustDecodeBounds=true to check dimensions
|
||||
final BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeByteArray(buffer, 0, buffer.length, options);
|
||||
|
||||
// If requested width/height were not specified - decode in full size.
|
||||
if (reqWidth > 0 && reqHeight > 0) {
|
||||
// Calculate inSampleSize
|
||||
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
|
||||
}
|
||||
else {
|
||||
options.inSampleSize = 1;
|
||||
}
|
||||
|
||||
// Decode bitmap with inSampleSize set
|
||||
options.inJustDecodeBounds = false;
|
||||
|
||||
// If we're running on Honeycomb or newer, try to use inBitmap
|
||||
if (Utils.hasHoneycomb()) {
|
||||
addInBitmapOptions(options, cache);
|
||||
}
|
||||
|
||||
return BitmapFactory.decodeByteArray(buffer, 0, buffer.length, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate an inSampleSize for use in a {@link BitmapFactory.Options} object when decoding
|
||||
* bitmaps using the decode* methods from {@link BitmapFactory}. This implementation calculates
|
||||
|
||||
@@ -5,9 +5,11 @@ package org.nativescript.widgets;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.*;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import org.nativescript.widgets.image.Fetcher;
|
||||
import org.nativescript.widgets.image.Worker;
|
||||
|
||||
/**
|
||||
* @author hhristov
|
||||
*
|
||||
@@ -23,6 +25,16 @@ public class ImageView extends android.widget.ImageView {
|
||||
|
||||
private float rotationAngle;
|
||||
|
||||
private Matrix mMatrix;
|
||||
private Bitmap mBitmap;
|
||||
private String mUri;
|
||||
private int mDecodeWidth;
|
||||
private int mDecodeHeight;
|
||||
private boolean mUseCache;
|
||||
private boolean mAsync;
|
||||
private Worker.OnImageLoadedListener mListener;
|
||||
private boolean mAttachedToWindow = false;
|
||||
|
||||
public float getRotationAngle() {
|
||||
return rotationAngle;
|
||||
}
|
||||
@@ -38,6 +50,23 @@ public class ImageView extends android.widget.ImageView {
|
||||
this.setScaleType(ScaleType.FIT_CENTER);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
mAttachedToWindow = true;
|
||||
super.onAttachedToWindow();
|
||||
this.loadImage();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
mAttachedToWindow = false;
|
||||
super.onDetachedFromWindow();
|
||||
if (mUri != null) {
|
||||
// Clear the bitmap as we are not in the visual tree.
|
||||
this.setImageBitmap(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
|
||||
@@ -132,21 +161,30 @@ public class ImageView extends android.widget.ImageView {
|
||||
}
|
||||
}
|
||||
|
||||
private Matrix mMatrix;
|
||||
private Bitmap pBitmap;
|
||||
public void setUri(String uri, int decodeWidth, int decodeHeight, boolean useCache, boolean async, Worker.OnImageLoadedListener listener) {
|
||||
mUri = uri;
|
||||
mDecodeWidth = decodeWidth;
|
||||
mDecodeHeight = decodeHeight;
|
||||
mUseCache = useCache;
|
||||
mAsync = async;
|
||||
mListener = listener;
|
||||
if (mAttachedToWindow) {
|
||||
loadImage();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadImage() {
|
||||
Fetcher fetcher = Fetcher.getInstance(this.getContext());
|
||||
if (mUri != null && fetcher != null) {
|
||||
// Get the Bitmap from cache.
|
||||
fetcher.loadImage(mUri, this, mDecodeWidth, mDecodeHeight, mUseCache, mAsync, mListener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImageBitmap(Bitmap bm) {
|
||||
super.setImageBitmap(bm);
|
||||
this.pBitmap = bm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImageDrawable(Drawable drawable) {
|
||||
super.setImageDrawable(drawable);
|
||||
if (drawable instanceof BitmapDrawable) {
|
||||
this.pBitmap = ((BitmapDrawable)drawable).getBitmap();
|
||||
}
|
||||
this.mBitmap = bm;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -185,8 +223,8 @@ public class ImageView extends android.widget.ImageView {
|
||||
|
||||
float viewWidth = this.getWidth() - (2 * roundedBorderWidth);
|
||||
float viewHeight = this.getHeight() - (2 * roundedBorderWidth);
|
||||
float bitmapWidth = (float) pBitmap.getWidth();
|
||||
float bitmapHeight = (float) pBitmap.getHeight();
|
||||
float bitmapWidth = (float) mBitmap.getWidth();
|
||||
float bitmapHeight = (float) mBitmap.getHeight();
|
||||
|
||||
float scaleX;
|
||||
float scaleY;
|
||||
@@ -223,7 +261,7 @@ public class ImageView extends android.widget.ImageView {
|
||||
matrix.postRotate(rotationDegree);
|
||||
matrix.postTranslate(viewWidth / 2 + roundedBorderWidth, viewHeight / 2 + roundedBorderWidth);
|
||||
|
||||
canvas.drawBitmap(this.pBitmap, matrix, null);
|
||||
canvas.drawBitmap(this.mBitmap, matrix, null);
|
||||
}
|
||||
else {
|
||||
super.onDraw(canvas);
|
||||
|
||||
@@ -373,5 +373,21 @@ public class ViewHelper {
|
||||
view.setZ(value);
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(21)
|
||||
public static float getLetterspacing(android.widget.TextView textView) {
|
||||
if (ViewHelper.version >= 21) {
|
||||
return textView.getLetterSpacing();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@TargetApi(21)
|
||||
public static void setLetterspacing(android.widget.TextView textView, float value) {
|
||||
if (ViewHelper.version >= 21) {
|
||||
textView.setLetterSpacing(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user