【问题标题】:Example using Androids lrucache使用 Android 的 lrucache 示例
【发布时间】:2012-07-24 04:06:05
【问题描述】:

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

【问题讨论】:

    标签: android android-lru-cache


    【解决方案1】:

    下面是我为使用 LruCache 制作的一个类,这是基于演示文稿Doing More With Less: Being a Good Android Citizen given at Google 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);
            }
        }
    }
    

    【讨论】:

    【解决方案2】:

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

    这是 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;
        }
    }
    

    这是您将位图保存到缓存的 Activity 中的代码:

    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...
        }
    

    【讨论】:

    • 简单,用一个例子很好地给出答案!
    • 我认为这应该被标记为答案!很好的例子,我刚刚用过。感谢分享!
    【解决方案3】:

    查看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);
    }
    

    【讨论】:

    • 好吧,我试着把它放在我的活动中,但有各种各样的错误,第一个是 LruCache 是原始类型。对泛型类型 LruCache 的引用应该是参数化的。从这里我觉得我必须扩展 LruCache 是这样吗?
    • 不需要扩展,LruCache是泛型类。阅读 Java 泛型以了解其含义。 Generic Types 上的本教程应该可以帮助您入门。
    • 我现在明白了,谢谢。但是我仍然无法成功地使这段代码工作
    • 我不了解 LruCache:什么时候应该覆盖它的“create(...)”方法?我的意思是,当您调用“get”时会调用它,并且您通常在 UI 线程上调用它,这对于创建依赖于慢速操作的东西(更不用说 Internet)是不安全的。
    • 给定的链接和链接中的 sn-p 是 LruCache 的“工作”、“完整”示例。而且我在帖子中也明确提到了链接,并且sn-p来自链接。它显然不是针对那些期待可以复制粘贴的代码的人,而是那些寻找方向的人。
    【解决方案4】:

    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);
                }
            }
        }
    }
    }
    

    【讨论】:

      【解决方案5】:

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

      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-08-29
        • 2012-05-22
        • 1970-01-01
        • 1970-01-01
        • 2014-01-07
        • 2012-12-05
        • 2015-10-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多