40

我需要帮助理解 androids LruCache。我想用来将图像加载到我的网格视图中,以使加载/滚动更好。有人可以使用 LruCache 发布示例代码吗?提前致谢。

4

5 回答 5

45

下面是我为使用 LruCache 制作的一个课程,它基于在 Google I/O 2012上的演示做更多事:做一个优秀的 Android 公民

查看电影以获取有关我在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);
        }
    }
}
于 2012-08-29T15:28:29.957 回答
29

我找到了一种非常适合我的非常简单的方法......

这是 Cache.java 类。在这个类中,静态getInstance()方法使我们能够在整个应用程序中只创建一个缓存实例。getLru()方法用于检索缓存的对象,稍后将展示如何使用它。此缓存是通用的,这意味着您可以将任何 Object 类型保存到其中。这里的缓存大小设置为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);
}

然后我也使用意图从第二个活动导航到第三个活动。在最后一个活动中,我将其他对象保存到我的缓存中,然后使用意图返回到第一个活动。一旦我回到第一个活动,该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...
    }
于 2014-10-27T19:19:20.547 回答
14

看看演示了使用的缓存位图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);
}
于 2012-07-24T04:41:21.330 回答
0

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);
            }
        }
    }
}
}
于 2015-08-29T08:37:33.430 回答
0

用于从自己的缓存中保存和检索位图的实用程序类。

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");
于 2019-04-14T12:52:12.203 回答