2012-07-24 4 views
30

Ich brauche Hilfe, Androiden LruCache zu verstehen. Ich möchte Bilder in meine Gridview laden, um das Laden/Scrollen zu erleichtern. Kann jemand bitte einen Beispielcode mit LruCache posten? Danke im Voraus.Beispiel mit Androiden Lrucache

Antwort

32

Im Folgenden eine Klasse I für die Verwendung von LRUCache gemacht wird dies auf der Grundlage der Präsentation Doing More With Less: Being a Good Android Citizen given at Google I/O 2012.

Schauen Sie sich den Film, um weitere Informationen über das, was ich in der TCImageLoader Klasse mache:

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

Basiert es auf dem Pre-Waben LruCache oder dem neueren? http://developer.android.com/reference/android/support/v4/util/LruCache.html oder http://developer.android.com/reference/android/util/LruCache.html – idish

+0

Seine Schätzung basiert auf der support-version, da die verwendete trimToSize nur mit API> 17 funktioniert. –

14

Werfen Sie einen Blick auf Caching Bitmaps wo die Verwendung von LruCache demonstriert wird.

Der relevante Teil des Codes von der Seite ist wie folgt: -

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

Nun, ich dies in meiner Tätigkeit versuchte Putting gegeben genommen, aber es gibt alle Arten von Fehlern der erste ist LRUCache ein Roh-Typ ist. Verweise auf den generischen Typ LruCache sollten parametrisiert werden. Von hier aus habe ich das Gefühl, dass ich LruCache erweitern muss ist das der Fall? – MobDev

+0

Es ist nicht notwendig zu erweitern, 'LruCache' ist eine generische Klasse. Lesen Sie über Java Generics, um zu verstehen, was das bedeutet. Dieses Tutorial zu [Generische Typen] (http://docs.oracle.com/javase/tutorial/java/generics/types.html) sollte Ihnen den Einstieg erleichtern. – Rajesh

+0

Ich sehe das jetzt, danke. Aber ich kann immer noch nicht erfolgreich diesen Code arbeiten – MobDev

18

ich eine wirklich einfache Möglichkeit gefunden haben, die perfekt für mich arbeiten ...

Diese ist die Cache.java-Klasse. In dieser Klasse ermöglicht es die statische Methode getInstance(), nur eine Cache-Instanz in der gesamten Anwendung zu erstellen. getLru() Methode wird verwendet, um das zwischengespeicherte Objekt abzurufen, es wird später gezeigt, wie man es benutzt. Dieser Cache ist generisch, dh Sie können einen beliebigen Objekttyp darin speichern. Die Cache-Speichergröße ist hier auf 1024. Es kann geändert werden, wenn es zu klein ist:

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

Dies ist der Code in Ihrer Tätigkeit ist, wo Sie die Bitmap in die Cache speichern:

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

Dies ist der Code, wo Sie die Bitmap aus dem Cache abgerufen werden, dann eine Imageview auf diese Bitmap gesetzt:

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

} 

das ist alles! Wie Sie sehen können, ist das ziemlich einfach und einfach.

  • Beispiel:

In meiner Anwendung, alle Ansichten werden in Klassenvariablen gespeichert, so dass sie von allen Methoden in der Klasse zu sehen. In meiner ersten Aktivität speichere ich die Bild-Bitmap in den Cache in einer onClickButton()-Methode, direkt bevor ich eine neue Aktivität mit Intent starte. Ich habe auch einen String-Wert in meinem Cache speichern:

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

Dann navigiere ich aus der zweiten Aktivität auf eine dritte Aktivität auch Absichten verwenden. In der letzten Aktivität speichere ich andere Objekte in meinem Cache und gehe dann mit einer Absicht zur ersten Aktivität zurück. Sobald ich wieder in der ersten Aktivität bin, wird die onCreate() Methode gestartet. Bei diesem Verfahren, überprüfe ich, ob mein Cache getrennt beliebigen Bitmap-Wert oder einen String-Wert hat (basierend auf meiner Anwendung Geschäft):

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

Einfache, gut präsentierte Antwort mit einem Beispiel! –

+0

Ich denke, das sollte als eine Antwort markiert werden! Gutes Beispiel und ich habe es gerade benutzt. Danke für das Teilen! – Mohammad

+0

Dies sollte als richtige Antwort markiert werden – GvSharma

0

https://techienotes.info/2015/08/28/caching-bitmaps-in-android-using-lrucache/

Dieser Link hat eine vollen Projekt-Anwendung mit Beispielbildern laden in Gridview mit LruCache.

Diese Klasse wird mit LRUCache und aus dem Code in dem Link

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