Android LruCacheを理解するのに助けが必要です。ロード/スクロールを改善するために、グリッドビューに画像をロードするために使用したいと思います。 LruCacheを使用してサンプルコードを投稿してください。前もって感謝します。
LruCacheを使用するために作成したクラスは次のとおりです。これはプレゼンテーションに基づいています より少ないリソースでより多くのことをする:良いことAndroid CitizenGoogle I/O 2012で指定 。
TCImageLoader
クラスで私がしていることの詳細については、ムービーをご覧ください。
public class TCImageLoader implements ComponentCallbacks2 {
private TCLruCache cache;
public TCImageLoader(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(
Context.ACTIVITY_SERVICE);
int maxKb = am.getMemoryClass() * 1024;
int limitKb = maxKb / 8; // 1/8th of total ram
cache = new TCLruCache(limitKb);
}
public void display(String url, ImageView imageview, int defaultresource) {
imageview.setImageResource(defaultresource);
Bitmap image = cache.get(url);
if (image != null) {
imageview.setImageBitmap(image);
}
else {
new SetImageTask(imageview).execute(url);
}
}
private class TCLruCache extends LruCache<String, Bitmap> {
public TCLruCache(int maxSize) {
super(maxSize);
}
@Override
protected int sizeOf(ImagePoolKey key, Bitmap value) {
int kbOfBitmap = value.getByteCount() / 1024;
return kbOfBitmap;
}
}
private class SetImageTask extends AsyncTask<String, Void, Integer> {
private ImageView imageview;
private Bitmap bmp;
public SetImageTask(ImageView imageview) {
this.imageview = imageview;
}
@Override
protected Integer doInBackground(String... params) {
String url = params[0];
try {
bmp = getBitmapFromURL(url);
if (bmp != null) {
cache.put(url, bmp);
}
else {
return 0;
}
} catch (Exception e) {
e.printStackTrace();
return 0;
}
return 1;
}
@Override
protected void onPostExecute(Integer result) {
if (result == 1) {
imageview.setImageBitmap(bmp);
}
super.onPostExecute(result);
}
private Bitmap getBitmapFromURL(String src) {
try {
URL url = new URL(src);
HttpURLConnection connection
= (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
}
@Override
public void onLowMemory() {
}
@Override
public void onTrimMemory(int level) {
if (level >= TRIM_MEMORY_MODERATE) {
cache.evictAll();
}
else if (level >= TRIM_MEMORY_BACKGROUND) {
cache.trimToSize(cache.size() / 2);
}
}
}
私にとって完璧に機能する本当に簡単な方法を見つけました...
これはCache.Javaクラスです。このクラスでは、静的なgetInstance()
メソッドにより、アプリケーション全体で1つのキャッシュインスタンスのみを作成できます。 getLru()
メソッドは、キャッシュされたオブジェクトを取得するために使用されます。後で使用方法が示されます。このキャッシュは汎用です。つまり、任意のオブジェクトタイプをキャッシュに保存できます。ここのキャッシュメモリサイズは1024に設定されています。小さすぎる場合は変更できます。
_import Android.support.v4.util.LruCache;
public class Cache {
private static Cache instance;
private LruCache<Object, Object> lru;
private Cache() {
lru = new LruCache<Object, Object>(1024);
}
public static Cache getInstance() {
if (instance == null) {
instance = new Cache();
}
return instance;
}
public LruCache<Object, Object> getLru() {
return lru;
}
}
_
これは、ビットマップをキャッシュに保存するアクティビティのコードです。
_public void saveBitmapToCahche(){
//The imageView that you want to save it's bitmap image resourse
ImageView imageView = (ImageView) findViewById(R.id.imageViewID);
//To get the bitmap from the imageView
Bitmap bitmap = ((BitmapDrawable)imageview.getDrawable()).getBitmap();
//Saving bitmap to cache. it will later be retrieved using the bitmap_image key
Cache.getInstance().getLru().put("bitmap_image", bitmap);
}
_
これは、キャッシュからビットマップを取得し、imageViewをこのビットマップに設定するコードです。
_public void retrieveBitmapFromCache(){
//The imageView that you want to set to the retrieved bitmap
ImageView imageView = (ImageView) findViewById(R.id.imageViewID);
//To get bitmap from cache using the key. Must cast retrieved cache Object to Bitmap
Bitmap bitmap = (Bitmap)Cache.getInstance().getLru().get("bitmap_image");
//Setting imageView to retrieved bitmap from cache
imageView.setImageBitmap(bitmap));
}
_
それで全部です!ご覧のとおり、これはかなり簡単でシンプルです。
私のアプリケーションでは、すべてのビューはクラス変数に保存されているため、クラス内のすべてのメソッドから見ることができます。最初のアクティビティでは、インテントを使用して新しいアクティビティを開始する直前に、onClickButton()
メソッドで画像ビットマップをキャッシュに保存します。また、キャッシュに文字列値を保存します。
_public void onClickButton(View v){
Bitmap bitmap = ((BitmapDrawable)imageView.getDrawable()).getBitmap();
String name = textEdit.getText().toString();
Cache.getInstance().getLru().put("bitmap_image", bitmap);
Cache.getInstance().getLru().put("name", name);
Intent i = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(i);
}
_
次に、インテントを使用して、2番目のアクティビティから3番目のアクティビティに移動します。最後のアクティビティでは、他のオブジェクトをキャッシュに保存し、インテントを使用して最初のアクティビティに戻ります。最初のアクティビティに戻ると、onCreate()
メソッドが開始されます。その方法では、キャッシュにビットマップ値または文字列値が個別にあるかどうかを確認します(アプリケーションのビジネスに基づいて)。
_public ImageView imageView;
public EditText editText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
//...Other code...
//The imageView that you want to save it's bitmap image resourse
imageView = (ImageView) findViewById(R.id.imageViewID);
//The editText that I want to save it's text into cache
editText = (EditText)findViewById(R.id.editTextID);
if(Cache.getInstance().getLru().get("name")!=null){
editText.setText(Cache.getInstance().getLru().get("name").toString());
}
if(Cache.getInstance().getLru().get("bitmap_image")!=null){
imageView.setImageBitmap((Bitmap)Cache.getInstance().getLru().get("bitmap_image"));
}
//...Other code...
}
_
Caching Bitmaps を見てください。ここでは LruCache
の使用が実証されています。
ページからのコードの関連部分は次のとおりです。
private LruCache mMemoryCache;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
// Get memory class of this device, exceeding this amount will throw an
// OutOfMemory exception.
final int memClass = ((ActivityManager) context.getSystemService(
Context.ACTIVITY_SERVICE)).getMemoryClass();
// Use 1/8th of the available memory for this memory cache.
final int cacheSize = 1024 * 1024 * memClass / 8;
mMemoryCache = new LruCache(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
// The cache size will be measured in bytes rather than number of items.
return bitmap.getByteCount();
}
};
...
}
public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (getBitmapFromMemCache(key) == null) {
mMemoryCache.put(key, bitmap);
}
}
public Bitmap getBitmapFromMemCache(String key) {
return mMemoryCache.get(key);
}
https://techienotes.info/2015/08/28/caching-bitmaps-in-Android-using-lrucache/
このリンクには、LruCacheを使用してGridviewに画像をロードするサンプルアプリケーションを含む完全なプロジェクトがあります。
このクラスはLruCacheを使用し、リンクで指定されたコードから取得します
public class ImageAdapter extends BaseAdapter{
private String TAG = getClass().getSimpleName();
Context mContext;
ArrayList<Uri> imageList;
private LruCache<String, Bitmap> mLruCache;
public ImageAdapter (Context context){
mContext = context;
//Find out maximum memory available to application
//1024 is used because LruCache constructor takes int in kilobytes
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
// Use 1/4th of the available memory for this memory cache.
final int cacheSize = maxMemory / 4;
Log.d(TAG, "max memory " + maxMemory + " cache size " + cacheSize);
// LruCache takes key-value pair in constructor
// key is the string to refer bitmap
// value is the stored bitmap
mLruCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
// The cache size will be measured in kilobytes
return bitmap.getByteCount() / 1024;
}
};
imageList = new ArrayList<Uri>();
//Change this directory to where the images are stored
String imagesFolderPath = Environment.getExternalStorageDirectory().getPath()+"/backups/";
File imageSrcDir = new File (imagesFolderPath);
// if directory not present, build it
if (!imageSrcDir.exists()){
imageSrcDir.mkdirs();
}
ArrayList<File> imagesInDir = getImagesFromDirectory(imageSrcDir);
for (File file: imagesInDir){
// imageList will hold Uri of all images
imageList.add(Uri.fromFile(file));
}
}
@Override
public int getCount() {
return imageList.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
/**
*
* @param position The position of the item within the
* adapter's data set of the item whose view we want.
* @param convertView it is the view to be reused
* @param parent The parent that this view will eventually be attached to
* @return a View corresponding to the data at the specified position.
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
Bitmap thumbnailImage = null;
if (convertView == null){
imageView = new ImageView(mContext);
imageView.setLayoutParams(
//150,150 is size of imageview to display image
new GridView.LayoutParams(150, 150));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
}
else {
imageView = (ImageView)convertView;
}
// Use the path as the key to LruCache
final String imageKey = imageList.get(position).toString();
//thumbnailImage is fetched from LRU cache
thumbnailImage = getBitmapFromMemCache(imageKey);
if (thumbnailImage == null){
// if asked thumbnail is not present it will be put into cache
BitmapWorkerTask task = new BitmapWorkerTask(imageView);
task.execute(imageKey);
}
imageView.setImageBitmap(thumbnailImage);
return imageView;
}
/**
* This function returns the files from a directory
* @param parentDirPath source directory in which images are located
* @return list of Files
*/
private ArrayList<File> getImagesFromDirectory (File parentDirPath){
ArrayList <File> listOfImages = new ArrayList<File>();
File [] fileArray = null;
if ( parentDirPath.isDirectory() ){//parentDirPath.exists() &&
// &&
// parentDirPath.canRead()){
fileArray = parentDirPath.listFiles();
}
if (fileArray == null){
return listOfImages; // return empty list
}
for (File file: fileArray){
if (file.isDirectory()){
listOfImages.addAll(getImagesFromDirectory(file));
}
else {
// Only JPEG and PNG formats are included
// for sake of simplicity
if (file.getName().endsWith("png") ||
file.getName().endsWith("jpg")){
listOfImages.add(file);
}
}
}
return listOfImages;
}
/**
* This function will return the scaled version of original image.
* Loading original images into thumbnail is wastage of computation
* and hence we will take put scaled version.
*/
private Bitmap getScaledImage (String imagePath){
Bitmap bitmap = null;
Uri imageUri = Uri.parse (imagePath);
try{
BitmapFactory.Options options = new BitmapFactory.Options();
/**
* inSampleSize flag if set to a value > 1,
* requests the decoder to sub-sample the original image,
* returning a smaller image to save memory.
* This is a much faster operation as decoder just reads
* every n-th pixel from given image, and thus
* providing a smaller scaled image.
* 'n' is the value set in inSampleSize
* which would be a power of 2 which is downside
* of this technique.
*/
options.inSampleSize = 4;
options.inScaled = true;
InputStream inputStream = mContext.getContentResolver().openInputStream(imageUri);
bitmap = BitmapFactory.decodeStream(inputStream, null, options);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return bitmap;
}
public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (getBitmapFromMemCache(key) == null) {
mLruCache.put(key, bitmap);
}
}
public Bitmap getBitmapFromMemCache(String key) {
return mLruCache.get(key);
}
class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
public BitmapWorkerTask(ImageView imageView) {
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference<ImageView>(imageView);
}
@Override
protected Bitmap doInBackground(String... params) {
final Bitmap bitmap = getScaledImage(params[0]);
addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);
return bitmap;
}
// onPostExecute() sets the bitmap fetched by doInBackground();
@Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = (ImageView)imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}
}
}
独自のキャッシュからビットマップを保存および取得するユーティリティクラス。
package com.roomco.Android.utils;
import Android.graphics.Bitmap;
import Android.support.v4.util.LruCache;
public class MyCache {
private static MyCache instance;
private LruCache<Object, Object> lru;
private MyCache() {
lru = new LruCache<Object, Object>(1024);
}
public static MyCache getInstance() {
if (instance == null) {
instance = new MyCache();
}
return instance;
}
public LruCache<Object, Object> getLru() {
return lru;
}
public void saveBitmapToCahche(String key, Bitmap bitmap){
MyCache.getInstance().getLru().put(key, bitmap);
}
public Bitmap retrieveBitmapFromCache(String key){
Bitmap bitmap = (Bitmap)MyCache.getInstance().getLru().get(key);
return bitmap;
}
}
使用法:
//Save bitmap in cache
MyCache.getInstance().saveBitmapToCahche("your_key",bitmap);
// Get bitmap from cache
MyCache.getInstance().retrieveBitmapFromCache("your_key");