जवाबों:
और अब पंचलाइन: सिस्टम कैश का उपयोग करें।
URL url = new URL(strUrl);
URLConnection connection = url.openConnection();
connection.setUseCaches(true);
Object response = connection.getContent();
if (response instanceof Bitmap) {
Bitmap bitmap = (Bitmap)response;
}
ब्राउज़र के साथ साझा की गई मेमोरी और फ्लैश-रोम कैश दोनों प्रदान करता है।
grr। काश, किसी ने मुझे बताया होता कि इससे पहले कि मैं अपना कैश मैनेजर लिखता।
connection.getContent()
हमेशा मेरे लिए एक InputStream देता है, मैं क्या गलत कर रहा हूँ?
Bitmap response = BitmapFactory.decodeStream((InputStream)connection.getContent());
connection.setUseCaches
ऊपर के सुरुचिपूर्ण समाधान के बारे में : दुख की बात है, यह कुछ अतिरिक्त प्रयास के बिना काम नहीं करेगा। आपको एक ResponseCache
प्रयोग स्थापित करने की आवश्यकता होगी ResponseCache.setDefault
। अन्यथा, HttpURLConnection
चुपचाप setUseCaches(true)
बिट को नजरअंदाज कर देगा ।
विवरण के लिए टिप्पणियों को सबसे ऊपर FileResponseCache.java
देखें:
(मैं इसे एक टिप्पणी में पोस्ट करूंगा, लेकिन मेरे पास स्पष्ट रूप से पर्याप्त कर्म नहीं है।)
HttpResponseCache
, तो आप HttpResponseCache.getHitCount()
रिटर्निंग ० प्राप्त कर सकते हैं । मुझे यकीन नहीं है, लेकिन मुझे लगता है कि ऐसा इसलिए है क्योंकि आप जिस वेबसर्वर से अनुरोध कर रहे हैं, वह उस स्थिति में कैशिंग हेडर का उपयोग नहीं करता है। वैसे भी कैशिंग कार्य करने के लिए, उपयोग करें connection.addRequestProperty("Cache-Control", "max-stale=" + MAX_STALE_CACHE);
।
.getContent()
विधि का उपयोग करते समय एचयूसी लटका होगा क्योंकि 304 प्रतिक्रियाओं में आरएफसी मानक द्वारा संबद्ध प्रतिक्रिया निकाय नहीं है।
उन्हें बिटमैप में परिवर्तित करें और फिर उन्हें एक संग्रह (हैशपॉप, सूची आदि) में संग्रहीत करें या आप उन्हें एसडीकार्ड पर लिख सकते हैं।
जब पहले दृष्टिकोण का उपयोग करके उन्हें एप्लिकेशन स्पेस में संग्रहीत किया जाता है, तो आप उन्हें java.lang.ref.oft.SoftReference के आसपास लपेटना चाह सकते हैं, खासकर यदि उनकी संख्या बड़ी है (ताकि वे संकट के दौरान एकत्र किए गए कचरा हों)। यह हालांकि एक रीलोड जारी कर सकता है।
HashMap<String,SoftReference<Bitmap>> imageCache =
new HashMap<String,SoftReference<Bitmap>>();
एसडीकार्ड पर उन्हें लिखने के लिए एक रिलोड की आवश्यकता नहीं होगी; सिर्फ एक उपयोगकर्ता-अनुमति।
Uri
पथ संदर्भ प्राप्त करने का सुझाव दूंगा जिसे आप ImageView
और अन्य कस्टम दृश्यों को पास कर सकते हैं । क्योंकि हर बार आप compress
गुणवत्ता खो देंगे। बेशक यह केवल हानिपूर्ण एल्गोरिदम के लिए सच है। यह विधि आपको फ़ाइल के हैश को स्टोर करने की अनुमति भी देती है और अगली बार जब आप सर्वर If-None-Match
और ETag
हेडर के माध्यम से फाइल के लिए अनुरोध करते हैं तो इसका उपयोग कर सकते हैं ।
LruCache
कुशलतापूर्वक कैश छवियों का उपयोग करें । आप Android डेवलपर साइटLruCache
से पढ़ सकते हैं
मैंने Android में Images Download और caching के लिए नीचे दिए गए समाधान का उपयोग किया है। आप नीचे दिए गए चरणों का अनुसरण कर सकते हैं:
चरण 1:
कक्षा नामांकित करें ImagesCache
। मैंने उपयोग किया हैSingleton object for this class
import android.graphics.Bitmap;
import android.support.v4.util.LruCache;
public class ImagesCache
{
private LruCache<String, Bitmap> imagesWarehouse;
private static ImagesCache cache;
public static ImagesCache getInstance()
{
if(cache == null)
{
cache = new ImagesCache();
}
return cache;
}
public void initializeCache()
{
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() /1024);
final int cacheSize = maxMemory / 8;
System.out.println("cache size = "+cacheSize);
imagesWarehouse = new LruCache<String, Bitmap>(cacheSize)
{
protected int sizeOf(String key, Bitmap value)
{
// The cache size will be measured in kilobytes rather than number of items.
int bitmapByteCount = value.getRowBytes() * value.getHeight();
return bitmapByteCount / 1024;
}
};
}
public void addImageToWarehouse(String key, Bitmap value)
{
if(imagesWarehouse != null && imagesWarehouse.get(key) == null)
{
imagesWarehouse.put(key, value);
}
}
public Bitmap getImageFromWarehouse(String key)
{
if(key != null)
{
return imagesWarehouse.get(key);
}
else
{
return null;
}
}
public void removeImageFromWarehouse(String key)
{
imagesWarehouse.remove(key);
}
public void clearCache()
{
if(imagesWarehouse != null)
{
imagesWarehouse.evictAll();
}
}
}
चरण 2:
DownloadImageTask नाम का एक और वर्ग बनाते हैं जिसका उपयोग अगर बिटमैप कैश में उपलब्ध नहीं है तो इसे यहाँ से डाउनलोड किया जाएगा:
public class DownloadImageTask extends AsyncTask<String, Void, Bitmap>
{
private int inSampleSize = 0;
private String imageUrl;
private BaseAdapter adapter;
private ImagesCache cache;
private int desiredWidth, desiredHeight;
private Bitmap image = null;
private ImageView ivImageView;
public DownloadImageTask(BaseAdapter adapter, int desiredWidth, int desiredHeight)
{
this.adapter = adapter;
this.cache = ImagesCache.getInstance();
this.desiredWidth = desiredWidth;
this.desiredHeight = desiredHeight;
}
public DownloadImageTask(ImagesCache cache, ImageView ivImageView, int desireWidth, int desireHeight)
{
this.cache = cache;
this.ivImageView = ivImageView;
this.desiredHeight = desireHeight;
this.desiredWidth = desireWidth;
}
@Override
protected Bitmap doInBackground(String... params)
{
imageUrl = params[0];
return getImage(imageUrl);
}
@Override
protected void onPostExecute(Bitmap result)
{
super.onPostExecute(result);
if(result != null)
{
cache.addImageToWarehouse(imageUrl, result);
if(ivImageView != null)
{
ivImageView.setImageBitmap(result);
}
else if(adapter != null)
{
adapter.notifyDataSetChanged();
}
}
}
private Bitmap getImage(String imageUrl)
{
if(cache.getImageFromWarehouse(imageUrl) == null)
{
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inSampleSize = inSampleSize;
try
{
URL url = new URL(imageUrl);
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
InputStream stream = connection.getInputStream();
image = BitmapFactory.decodeStream(stream, null, options);
int imageWidth = options.outWidth;
int imageHeight = options.outHeight;
if(imageWidth > desiredWidth || imageHeight > desiredHeight)
{
System.out.println("imageWidth:"+imageWidth+", imageHeight:"+imageHeight);
inSampleSize = inSampleSize + 2;
getImage(imageUrl);
}
else
{
options.inJustDecodeBounds = false;
connection = (HttpURLConnection)url.openConnection();
stream = connection.getInputStream();
image = BitmapFactory.decodeStream(stream, null, options);
return image;
}
}
catch(Exception e)
{
Log.e("getImage", e.toString());
}
}
return image;
}
चरण 3: अपने Activity
या से उपयोगAdapter
नोट: यदि आप Activity
कक्षा से url से छवि लोड करना चाहते हैं । दूसरे कंस्ट्रक्टर का उपयोग करें DownloadImageTask
, लेकिन यदि आप Adapter
पहले कंस्ट्रक्टर के उपयोग से छवि प्रदर्शित करना चाहते हैं DownloadImageTask
(उदाहरण के लिए आपके पास एक छवि है ListView
और आप 'एडेप्टर' से छवि सेट कर रहे हैं)
गतिविधि से उपयोग:
ImageView imv = (ImageView) findViewById(R.id.imageView);
ImagesCache cache = ImagesCache.getInstance();//Singleton instance handled in ImagesCache class.
cache.initializeCache();
String img = "your_image_url_here";
Bitmap bm = cache.getImageFromWarehouse(img);
if(bm != null)
{
imv.setImageBitmap(bm);
}
else
{
imv.setImageBitmap(null);
DownloadImageTask imgTask = new DownloadImageTask(cache, imv, 300, 300);//Since you are using it from `Activity` call second Constructor.
imgTask.execute(img);
}
ADAPTER से उपयोग:
ImageView imv = (ImageView) rowView.findViewById(R.id.imageView);
ImagesCache cache = ImagesCache.getInstance();
cache.initializeCache();
String img = "your_image_url_here";
Bitmap bm = cache.getImageFromWarehouse(img);
if(bm != null)
{
imv.setImageBitmap(bm);
}
else
{
imv.setImageBitmap(null);
DownloadImageTask imgTask = new DownloadImageTask(this, 300, 300);//Since you are using it from `Adapter` call first Constructor.
imgTask.execute(img);
}
ध्यान दें:
cache.initializeCache()
आप इस कथन का उपयोग अपने आवेदन की पहली गतिविधि में कर सकते हैं। एक बार जब आप कैश को इनिशियलाइज़ कर लेते हैं तो आपको हर बार इसे इनिशियलाइज़ करने की आवश्यकता नहीं होगी यदि आप ImagesCache
इंस्टेंस का उपयोग कर रहे हैं ।
मैं चीजों को समझाने में कभी भी अच्छा नहीं हूं लेकिन आशा करता हूं कि यह शुरुआती लोगों की मदद करेगा कि कैसे LruCache
और इसके उपयोग को कैश किया जाए :)
संपादित करें:
अब एक दिन बहुत ही प्रसिद्ध पुस्तकालयों के रूप में जाना जाता है Picasso
और Glide
जिसका उपयोग एंड्रॉइड ऐप में बहुत कुशलता से छवियों को लोड करने के लिए किया जा सकता है। Android और Glide For Android के लिए यह बहुत ही सरल और उपयोगी लाइब्रेरी पिकासो आज़माएँ । आपको कैश छवियों के बारे में चिंता करने की आवश्यकता नहीं है।
पिकासो आपके आवेदन में परेशानी मुक्त छवि लोड करने की अनुमति देता है - अक्सर कोड की एक पंक्ति में!
ग्लाइड, पिकासो की तरह, कई स्रोतों से छवियों को लोड और प्रदर्शित कर सकते हैं, जबकि कैशिंग का भी ध्यान रखते हैं और छवि हेरफेर करते समय कम मेमोरी प्रभाव रखते हैं। इसका उपयोग आधिकारिक Google ऐप द्वारा किया गया है (जैसे Google I / O 2015 के लिए ऐप) और पिकासो की तरह ही लोकप्रिय है। इस श्रृंखला में, हम पिकासो पर ग्लाइड के मतभेदों और लाभों का पता लगाने जा रहे हैं।
आप ग्लाइड और पिकासो के बीच अंतर के लिए ब्लॉग पर भी जा सकते हैं
if(cache == null)
जिसने मेरी समस्या हल कर दी! :)
एक छवि डाउनलोड करने और मेमोरी कार्ड में सहेजने के लिए आप इसे इस तरह से कर सकते हैं।
//First create a new URL object
URL url = new URL("http://www.google.co.uk/logos/holiday09_2.gif")
//Next create a file, the example below will save to the SDCARD using JPEG format
File file = new File("/sdcard/example.jpg");
//Next create a Bitmap object and download the image to bitmap
Bitmap bitmap = BitmapFactory.decodeStream(url.openStream());
//Finally compress the bitmap, saving to the file previously created
bitmap.compress(CompressFormat.JPEG, 100, new FileOutputStream(file));
अपने मैनिफ़ेस्ट में इंटरनेट की अनुमति जोड़ना न भूलें:
<uses-permission android:name="android.permission.INTERNET" />
मैं droidfu की छवि कैश का उपयोग करने पर विचार करूंगा। यह इन-मेमोरी और डिस्क-आधारित छवि कैश दोनों को लागू करता है। आपको एक WebImageView भी मिलता है जो ImageCache लाइब्रेरी का लाभ उठाता है।
यहाँ droidfu और WebImageView का पूरा विवरण दिया गया है: http://brainflush.wordpress.com/2009/11/23/droid-fu-part-2-webimageview-and-webgalleryadcape/
मैंने SoftReferences की कोशिश की है, वे एंड्रॉइड में बहुत आक्रामक रूप से पुन: प्रशंसित हैं कि मुझे लगा कि उनका उपयोग करने का कोई मतलब नहीं था
SoftReference
एस एकत्रित करने पर Dalvik की GC बहुत आक्रामक है । वे LruCache
इसके बजाय उनके उपयोग की सलाह देते हैं ।
जैसा कि थंडर रैबिट ने सुझाव दिया था, ImageDownloader नौकरी के लिए सबसे अच्छा है। मुझे कक्षा में थोड़ा बदलाव भी आया:
http://theandroidcoder.com/utilities/android-image-download-and-caching/
दोनों के बीच मुख्य अंतर यह है कि ImageDownloader एंड्रॉइड कैशिंग सिस्टम का उपयोग करता है, और संशोधित व्यक्ति कैशिंग के रूप में आंतरिक और बाहरी भंडारण का उपयोग करता है, कैश्ड छवियों को अनिश्चित काल तक या जब तक उपयोगकर्ता इसे मैन्युअल रूप से हटा नहीं देता है। लेखक ने एंड्रॉइड 2.1 संगतता का भी उल्लेख किया है।
जोए का यह एक अच्छा कैच है। ऊपर दिए गए कोड के उदाहरण में दो समस्याएं हैं - एक - प्रतिक्रिया ऑब्जेक्ट बिटमैप का उदाहरण नहीं है (जब मेरा URL एक ऐसे संदर्भ संदर्भित करता है जैसे http: \ website.com \ image.jpg, इसका एक
org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl $ LimitedInputStream)।
दूसरा, जैसा कि जो बताते हैं, कोई कैशिंग प्रतिक्रिया कैश को कॉन्फ़िगर किए बिना नहीं होता है। एंड्रॉइड डेवलपर्स को अपने स्वयं के कैश को रोल करने के लिए छोड़ दिया जाता है। यहां ऐसा करने के लिए एक उदाहरण है, लेकिन यह केवल स्मृति में कैश करता है, जो वास्तव में पूर्ण समाधान नहीं है।
http://codebycoffee.com/2010/06/29/using-responsecache-in-an-android-app/
URLConnection कैशिंग API यहां वर्णित है:
http://download.oracle.com/javase/6/docs/technotes/guides/net/http-cache.html
मुझे अभी भी लगता है कि यह इस मार्ग पर जाने के लिए एक ठीक समाधान है - लेकिन आपको अभी भी कैश लिखना होगा। मज़ा की तरह लगता है, लेकिन मैं सुविधाओं लिखना होगा।
इसके बारे में Android के आधिकारिक प्रशिक्षण अनुभाग में एक विशेष प्रविष्टि है: http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
अनुभाग काफी नया है, यह तब नहीं था जब सवाल पूछा गया था।
सुझाया गया समाधान एक LruCache का उपयोग करना है। उस वर्ग को हनीकॉम्ब पर पेश किया गया था, लेकिन यह संगतता पुस्तकालय पर भी शामिल है।
आप अधिकतम संख्या या प्रविष्टियाँ सेट करके एक 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);
}
पहले SoftReferences एक अच्छा विकल्प थे, लेकिन अब आधिकारिक पृष्ठ से उद्धृत नहीं:
नोट: अतीत में, एक लोकप्रिय मेमोरी कैश कार्यान्वयन एक सॉफ्टरेंफरेंस या वीकररेंस बिटमैप कैश था, हालांकि यह अनुशंसित नहीं है। एंड्रॉइड 2.3 (एपीआई लेवल 9) से शुरू होने वाले कचरा कलेक्टर नरम / कमजोर संदर्भों को इकट्ठा करने के साथ अधिक आक्रामक होते हैं जो उन्हें काफी अप्रभावी बनाता है। इसके अलावा, एंड्रॉइड 3.0 (एपीआई स्तर 11) से पहले, बिटमैप के बैकिंग डेटा को देशी मेमोरी में संग्रहीत किया गया था, जो कि एक पूर्वसूचक तरीके से जारी नहीं किया गया है, संभवतः किसी एप्लिकेशन को इसकी मेमोरी सीमा और क्रैश से अधिक हो सकता है।
सर्गेई तारासेविच द्वारा यूनिवर्सल इमेज लोडर लाइब्रेरी का उपयोग करने पर विचार करें । यह इसके साथ आता है:
यूनिवर्सल इमेज लोडर निम्नलिखित कैश कॉन्फ़िगरेशन के साथ, डाउनलोड की गई छवियों के लिए विस्तृत कैश प्रबंधन की अनुमति देता है:
UsingFreqLimitedMemoryCache
: कैश आकार की सीमा पार होने पर कम से कम अक्सर उपयोग किए जाने वाले बिटमैप को हटा दिया जाता है।LRULimitedMemoryCache
: कैश आकार की सीमा पार होने पर हाल ही में उपयोग किया गया बिटमैप हटा दिया जाता है।FIFOLimitedMemoryCache
: कैश आकार की सीमा पार होने पर फीफो नियम को हटाने के लिए उपयोग किया जाता है।LargestLimitedMemoryCache
: कैश आकार की सीमा पार होने पर सबसे बड़ा बिटमैप हटा दिया जाता है।LimitedAgeMemoryCache
: कैश्ड ऑब्जेक्ट तब हटा दिया जाता है जब उसकी आयु निर्धारित मान से अधिक हो जाती है ।WeakMemoryCache
: बिटमैप्स के केवल कमजोर संदर्भों के साथ एक मेमोरी कैश।एक सरल उपयोग उदाहरण:
ImageView imageView = groupView.findViewById(R.id.imageView);
String imageUrl = "http://site.com/image.png";
ImageLoader imageLoader = ImageLoader.getInstance();
imageLoader.init(ImageLoaderConfiguration.createDefault(context));
imageLoader.displayImage(imageUrl, imageView);
यह उदाहरण डिफ़ॉल्ट का उपयोग करता है UsingFreqLimitedMemoryCache
।
मेरे लिए वास्तव में जो काम किया गया वह मेरे मुख्य वर्ग पर ResponseCache की स्थापना कर रहा था:
try {
File httpCacheDir = new File(getApplicationContext().getCacheDir(), "http");
long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
HttpResponseCache.install(httpCacheDir, httpCacheSize);
} catch (IOException e) { }
तथा
connection.setUseCaches(true);
बिटमैप डाउनलोड करते समय।
http://practicaldroid.blogspot.com/2013/01/utilizing-http-response-cache.html
Google के lib-for-android में छवि और फ़ाइल कैश प्रबंधित करने के लिए एक अच्छा पुस्तकालय है।
मैं कुछ समय से इससे कुश्ती कर रहा था; SoftReferences का उपयोग करने वाले उत्तर उनके डेटा को बहुत तेज़ी से खो देंगे। उन अनुरोधों के बारे में जो सुझाव देते हैं कि रिक्वेस्ट कैश करने में बहुत गड़बड़ हो गई थी, साथ ही मुझे कभी भी इसका पूरा उदाहरण नहीं मिला।
लेकिन ImageDownloader.java मेरे लिए अद्भुत काम करता है। क्षमता तक पहुंचने तक या शुद्ध समय समाप्त होने तक यह एक हैशपॉप का उपयोग करता है, फिर चीजें सॉफ्टरफेन्स में स्थानांतरित हो जाती हैं, जिससे दोनों दुनिया का सबसे अच्छा उपयोग होता है।
मेरा सुझाव है कि इग्निशन इस और भी बेहतर Droid फू से है
https://github.com/kaeppler/ignition
https://github.com/kaeppler/ignition/wiki/Sample-applications
यहां तक कि बाद में जवाब दिया, लेकिन मैंने एक एंड्रॉइड इमेज मैनेजर लिखा जो कैशिंग को पारदर्शी रूप से (मेमोरी और डिस्क) हैंडल करता है। कोड Github https://github.com/felipecsl/Android-ImageManager पर है
: स्वर्गीय जवाब है, लेकिन मुझे लगता है मैं अपनी साइट के लिए एक लिंक जोड़ना चाहिए क्योंकि मैं एक ट्यूटोरियल के लिए एंड्रॉयड एक छवि कैश करने के लिए लिखा है सोचा http://squarewolf.nl/2010/11/android-image-cache/ अद्यतन: स्रोत पुराना होने के कारण पृष्ठ को ऑफ़लाइन ले लिया गया है। मैं इग्निशन का उपयोग करने के लिए उसकी सलाह में @elenasys से जुड़ता हूं ।
तो उन सभी लोगों के लिए जो इस प्रश्न पर ठोकर खाते हैं और उन्होंने कोई हल नहीं निकाला है: आशा है कि आप आनंद लेंगे! = D
उत्तर देर से लेकिन मुझे लगता है कि यह पुस्तकालय कैशिंग छवियों के साथ बहुत मदद करेगा: https://github.com/crypticminds/ColdStorage ।
बस छवि को @LoadCache (R.id.id_of_my_image_view, "URL_to_downlaod_image_from) के साथ एनोटेट करें और यह छवि को डाउनलोड करने और छवि दृश्य में लोड करने का ध्यान रखेगा। आप एक प्लेसहोल्डर छवि और लोडिंग एनीमेशन भी निर्दिष्ट कर सकते हैं।
एनोटेशन का विस्तृत दस्तावेज यहां मौजूद है: - https://github.com/crypticminds/ColdStorage/wiki/@LoadImage-annotation