added image cache for emoji images
This commit is contained in:
parent
96f6aba71e
commit
af381a8feb
|
@ -11,11 +11,9 @@ import org.nuclearfog.twidda.backend.api.Connection;
|
||||||
import org.nuclearfog.twidda.backend.api.ConnectionException;
|
import org.nuclearfog.twidda.backend.api.ConnectionException;
|
||||||
import org.nuclearfog.twidda.backend.api.ConnectionManager;
|
import org.nuclearfog.twidda.backend.api.ConnectionManager;
|
||||||
import org.nuclearfog.twidda.backend.helper.MediaStatus;
|
import org.nuclearfog.twidda.backend.helper.MediaStatus;
|
||||||
|
import org.nuclearfog.twidda.backend.utils.ImageCache;
|
||||||
import org.nuclearfog.twidda.model.Emoji;
|
import org.nuclearfog.twidda.model.Emoji;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
@ -27,18 +25,15 @@ import java.util.TreeMap;
|
||||||
*/
|
*/
|
||||||
public class EmojiLoader extends AsyncExecutor<EmojiLoader.EmojiParam, EmojiLoader.EmojiResult> {
|
public class EmojiLoader extends AsyncExecutor<EmojiLoader.EmojiParam, EmojiLoader.EmojiResult> {
|
||||||
|
|
||||||
private static final String FOLDER = "emojis";
|
|
||||||
|
|
||||||
private File imageFolder;
|
|
||||||
private Connection connection;
|
private Connection connection;
|
||||||
|
private ImageCache cache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public EmojiLoader(Context context) {
|
public EmojiLoader(Context context) {
|
||||||
connection = ConnectionManager.getDefaultConnection(context);
|
connection = ConnectionManager.getDefaultConnection(context);
|
||||||
imageFolder = new File(context.getExternalCacheDir(), FOLDER);
|
cache = ImageCache.getInstance(context);
|
||||||
imageFolder.mkdirs();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,37 +41,17 @@ public class EmojiLoader extends AsyncExecutor<EmojiLoader.EmojiParam, EmojiLoad
|
||||||
@Override
|
@Override
|
||||||
protected EmojiResult doInBackground(@NonNull EmojiParam param) {
|
protected EmojiResult doInBackground(@NonNull EmojiParam param) {
|
||||||
try {
|
try {
|
||||||
Map<String, File> files = new TreeMap<>();
|
|
||||||
Map<String, Bitmap> result = new TreeMap<>();
|
Map<String, Bitmap> result = new TreeMap<>();
|
||||||
// cache all local image files first
|
|
||||||
File[] imageFiles = imageFolder.listFiles();
|
|
||||||
if (imageFiles != null) {
|
|
||||||
for (File file : imageFiles) {
|
|
||||||
files.put(file.getName(), file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (Emoji emoji : param.emojis) {
|
for (Emoji emoji : param.emojis) {
|
||||||
File file = files.get(emoji.getCode());
|
Bitmap icon = cache.getImage(emoji.getCode());
|
||||||
if (file == null) {
|
if (icon == null) {
|
||||||
// download image to cache
|
|
||||||
MediaStatus media = connection.downloadImage(emoji.getUrl());
|
MediaStatus media = connection.downloadImage(emoji.getUrl());
|
||||||
InputStream input = media.getStream();
|
InputStream input = media.getStream();
|
||||||
file = new File(imageFolder, emoji.getCode());
|
icon = BitmapFactory.decodeStream(input);
|
||||||
file.createNewFile();
|
cache.putImage(emoji.getCode(), icon);
|
||||||
FileOutputStream output = new FileOutputStream(file);
|
|
||||||
Bitmap icon = BitmapFactory.decodeStream(input);
|
|
||||||
icon.compress(Bitmap.CompressFormat.PNG, 1, output);
|
|
||||||
// resize image
|
|
||||||
icon = Bitmap.createScaledBitmap(icon, icon.getWidth() / icon.getHeight() * param.size, param.size, false);
|
|
||||||
result.put(emoji.getCode(), icon);
|
|
||||||
} else {
|
|
||||||
// load image from cache
|
|
||||||
FileInputStream inputStream = new FileInputStream(file);
|
|
||||||
Bitmap icon = BitmapFactory.decodeStream(inputStream);
|
|
||||||
// resize image
|
|
||||||
icon = Bitmap.createScaledBitmap(icon, icon.getWidth() / icon.getHeight() * param.size, param.size, false);
|
|
||||||
result.put(emoji.getCode(), icon);
|
|
||||||
}
|
}
|
||||||
|
icon = Bitmap.createScaledBitmap(icon, icon.getWidth() / icon.getHeight() * param.size, param.size, false);
|
||||||
|
result.put(emoji.getCode(), icon);
|
||||||
}
|
}
|
||||||
return new EmojiResult(result, null);
|
return new EmojiResult(result, null);
|
||||||
} catch (ConnectionException exception) {
|
} catch (ConnectionException exception) {
|
||||||
|
@ -90,6 +65,7 @@ public class EmojiLoader extends AsyncExecutor<EmojiLoader.EmojiParam, EmojiLoad
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public static class EmojiParam {
|
public static class EmojiParam {
|
||||||
|
|
||||||
Emoji[] emojis;
|
Emoji[] emojis;
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
package org.nuclearfog.twidda.backend.utils;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.util.LruCache;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents an image cache for emoji icons
|
||||||
|
* There are both, image cache and file cache. If image doesn't exist in the cache, the file cache is used to search for the file.
|
||||||
|
* A new image will be cached and saved as file to the local cache storage.
|
||||||
|
*
|
||||||
|
* @author nuclearfog
|
||||||
|
*/
|
||||||
|
public class ImageCache {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* size of the lru cache (max entry count)
|
||||||
|
*/
|
||||||
|
private static final int SIZE = 64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* folder name of the local cache
|
||||||
|
*/
|
||||||
|
private static final String FOLDER = "images";
|
||||||
|
|
||||||
|
private static ImageCache instance;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private File imageFolder;
|
||||||
|
|
||||||
|
private LruCache<String, Bitmap> cache;
|
||||||
|
|
||||||
|
private Map<String, File> files;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param context context used to determine cache folder path
|
||||||
|
*/
|
||||||
|
private ImageCache(Context context) {
|
||||||
|
files = new TreeMap<>();
|
||||||
|
cache = new LruCache<>(SIZE);
|
||||||
|
try {
|
||||||
|
imageFolder = new File(context.getExternalCacheDir(), FOLDER);
|
||||||
|
imageFolder.mkdirs();
|
||||||
|
File[] imageFiles = imageFolder.listFiles();
|
||||||
|
if (imageFiles != null) {
|
||||||
|
for (File file : imageFiles) {
|
||||||
|
files.put(file.getName(), file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SecurityException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* put image to cache and save as file if not exists
|
||||||
|
*
|
||||||
|
* @param key key of the image (tag)
|
||||||
|
* @param image image bitmap
|
||||||
|
*/
|
||||||
|
public void putImage(String key, Bitmap image) {
|
||||||
|
cache.put(key, image);
|
||||||
|
if (imageFolder != null && !files.containsKey(key)) {
|
||||||
|
try {
|
||||||
|
File file = new File(imageFolder, key);
|
||||||
|
file.createNewFile();
|
||||||
|
FileOutputStream output = new FileOutputStream(file);
|
||||||
|
image.compress(Bitmap.CompressFormat.PNG, 1, output);
|
||||||
|
files.put(key, file);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get image from cache or file
|
||||||
|
*
|
||||||
|
* @param key key of the image (tag)
|
||||||
|
* @return image bitmap or null if not found
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public Bitmap getImage(String key) {
|
||||||
|
Bitmap result = cache.get(key);
|
||||||
|
if (result == null) {
|
||||||
|
File file = files.get(key);
|
||||||
|
if (file != null) {
|
||||||
|
try {
|
||||||
|
FileInputStream inputStream = new FileInputStream(file);
|
||||||
|
result = BitmapFactory.decodeStream(inputStream);
|
||||||
|
cache.put(key, result);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create singleton instance of this class
|
||||||
|
*
|
||||||
|
* @return singleton instance of this class
|
||||||
|
*/
|
||||||
|
public static ImageCache getInstance(Context context) {
|
||||||
|
if (instance == null)
|
||||||
|
instance = new ImageCache(context);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue