2012-07-24 61 views
30

我需要幫助理解androids LruCache。我想用來加載圖像到我的gridview,使加載/滾動更好。有人可以使用LruCache發佈示例代碼。提前致謝。使用Android的示例lrucache

回答

32

下面是一類我使用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); 
     } 
    } 
} 
+0

它是基於pre-honeycomb LruCache還是更新的? http://developer.android.com/reference/android/support/v4/util/LruCache.html或http://developer.android.com/reference/android/util/LruCache.html – idish 2013-10-15 18:36:31

+0

其猜測它基於支持版本,因爲使用的trimToSize僅適用於API> 17。 – 2014-10-27 08:52:26

14

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

嗯,我試圖把這個在我的活動,但有錯誤的種種給出的代碼所採取的第一個是LruCache是​​原始類型。參考通用類型LruCache 應該參數化。從這裏我覺得我必須擴展LruCache 是這種情況嗎? – MobDev 2012-07-24 05:50:30

+0

不需要擴展,'LruCache'是一個泛型類。閱讀Java泛型,瞭解這意味着什麼。本教程[Generic Types](http://docs.oracle.com/javase/tutorial/java/generics/types.html)應該讓你開始。 – Rajesh 2012-07-24 05:56:20

+0

我明白了,謝謝。但是我仍然無法成功地使這個代碼工作 – MobDev 2012-07-24 07:32:25

18

我發現完美的我是一個工作非常簡單的方法...

這是Cache.java類。在這個類中,靜態的getInstance()方法使我們能夠在整個應用程序中只創建一個緩存實例。 getLru()方法用於檢索緩存的對象,它將在稍後顯示如何使用它。此緩存是通用的,這意味着您可以將任何對象類型保存到其中。

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

的高速緩存大小這裏設置爲1024,可如果它太小被改變這是從緩存中檢索位圖的代碼,然後將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... 
    } 
+0

簡單,很好的答案與一個例子! – 2015-02-22 04:54:52

+0

我認爲這應該被標記爲答案!很好的例子,我剛剛使用它。感謝分享! – Mohammad 2016-03-02 09:49:14

+0

這應該被標記爲正確答案 – GvSharma 2016-03-09 06:56:34

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