안드로이드 이미지 캐싱
웹에서 이미지를 다운로드 한 후 어떻게 캐시 할 수 있습니까?
이제 펀치 라인 : 시스템 캐시를 사용하십시오.
URL url = new URL(strUrl);
URLConnection connection = url.openConnection();
connection.setUseCaches(true);
Object response = connection.getContent();
if (response instanceof Bitmap) {
Bitmap bitmap = (Bitmap)response;
}
브라우저와 공유되는 메모리 및 플래시 ROM 캐시를 모두 제공합니다.
grr. 누군가 나에게 캐시 관리자를 작성하기 전에 나에게 말했으면 좋겠다.
connection.setUseCaches
위 의 우아한 솔루션 과 관련하여 슬프게도 추가 노력 없이는 작동하지 않습니다. ResponseCache
using 을 설치해야합니다 ResponseCache.setDefault
. 그렇지 않으면 비트 HttpURLConnection
를 자동으로 무시합니다 setUseCaches(true)
.
자세한 내용은 상단의 주석을 참조 FileResponseCache.java
하십시오.
(나는 이것을 의견에 게시 할 것이지만 분명히 충분한 업장이 없습니다.)
비트 맵으로 변환 한 다음 Collection (HashMap, List 등)에 저장하거나 SDcard에 쓸 수 있습니다.
첫 번째 방법을 사용하여 애플리케이션 공간에 저장하는 경우, 숫자가 큰 경우 (위기 동안 가비지 수집 됨) 구체적 으로 java.lang.ref.SoftReference 주위를 랩핑 할 수 있습니다 . 그래도 재로드가 발생할 수 있습니다.
HashMap<String,SoftReference<Bitmap>> imageCache =
new HashMap<String,SoftReference<Bitmap>>();
SDcard에 작성하면 다시로드 할 필요가 없습니다. 단지 사용자 권한.
LruCache
이미지를 효율적으로 캐시하는 데 사용 합니다. Android 개발자 사이트LruCache
에서 읽을 수 있습니다
안드로이드에서 이미지 다운로드 및 캐싱을 위해 아래 솔루션을 사용했습니다. 아래 단계를 수행 할 수 있습니다.
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);
}
어댑터 사용 :
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
안드로이드 응용 프로그램에서 매우 효율적으로 부하 이미지를 사용할 수 있습니다. 이 매우 간단하고 유용한 라이브러리 시도 안드로이드 피카소 와 글라이드를 들어 안드로이드 . 캐시 이미지에 대해 걱정할 필요가 없습니다.
Picasso는 응용 프로그램에서 번거롭지 않은 이미지 로딩을 허용합니다 (종종 한 줄의 코드로).
피카소와 마찬가지로 글라이드는 여러 소스에서 이미지를로드하고 표시 할 수 있으며 이미지 조작을 수행 할 때 캐싱을 관리하고 메모리 영향을 줄입니다. 공식 Google 앱 (Google I / O 2015 용 앱 등)에서 사용되었으며 Picasso만큼 인기가 있습니다. 이 시리즈에서는 피카소보다 글라이드의 차이점과 장점을 살펴 보겠습니다.
글라이드와 피카소의 차이점에 대한 블로그를 방문 할 수도 있습니다
이미지를 다운로드하여 메모리 카드에 저장하려면 다음과 같이하십시오.
//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의 이미지 캐시 사용을 고려할 것입니다. 인 메모리 및 디스크 기반 이미지 캐시를 모두 구현합니다. ImageCache 라이브러리를 활용하는 WebImageView도 얻을 수 있습니다.
Here is the full description of droidfu and WebImageView: http://brainflush.wordpress.com/2009/11/23/droid-fu-part-2-webimageview-and-webgalleryadapter/
I've tried SoftReferences, they are too aggressively reclaimed in android that I felt there was no point using them
As Thunder Rabbit suggested, ImageDownloader is the best one for the job. I also found a slight variation of the class at:
http://theandroidcoder.com/utilities/android-image-download-and-caching/
The main difference between the two is that the ImageDownloader uses the Android caching system, and the modified one uses internal and external storage as caching, keeping the cached images indefinitely or until the user removes it manually. The author also mentions Android 2.1 compatibility.
This is a good catch by Joe. The code example above has two problems - one - the response object isn't an instance of Bitmap (when my URL references a jpg, like http:\website.com\image.jpg, its a
org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl$LimitedInputStream).
Second, as Joe points out, no caching occurs without a response cache being configured. Android developers are left to roll their own cache. Here's an example for doing so, but it only caches in memory, which really isn't the full solution.
http://codebycoffee.com/2010/06/29/using-responsecache-in-an-android-app/
The URLConnection caching API is described here:
http://download.oracle.com/javase/6/docs/technotes/guides/net/http-cache.html
I still think this is an OK solution to go this route - but you still have to write a cache. Sounds like fun, but I'd rather write features.
There is a special entry on the official training section of Android about this: http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
The section is quite new, it was not there when the question was asked.
The suggested solution is to use a LruCache. That class was introduced on Honeycomb, but it is also included on the compatibility library.
You can initialize a LruCache by setting the maximum number or entries and it will automatically sort them your you and clean them less used ones when you go over the limit. Other than that it is used as a normal Map.
The sample code from the official page:
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);
}
Previously SoftReferences were a good alternative, but not anymore, quoting from the official page:
Note: In the past, a popular memory cache implementation was a SoftReference or WeakReference bitmap cache, however this is not recommended. Starting from Android 2.3 (API Level 9) the garbage collector is more aggressive with collecting soft/weak references which makes them fairly ineffective. In addition, prior to Android 3.0 (API Level 11), the backing data of a bitmap was stored in native memory which is not released in a predictable manner, potentially causing an application to briefly exceed its memory limits and crash.
Consider using Universal Image Loader library by Sergey Tarasevich. It comes with:
- Multithread image loading. It lets you can define the thread pool size
- Image caching in memory, on device's file sytem and SD card.
- Possibility to listen to loading progress and loading events
Universal Image Loader allows detailed cache management for downloaded images, with the following cache configurations:
UsingFreqLimitedMemoryCache
: The least frequently used bitmap is deleted when the cache size limit is exceeded.LRULimitedMemoryCache
: The least recently used bitmap is deleted when the cache size limit is exceeded.FIFOLimitedMemoryCache
: The FIFO rule is used for deletion when the cache size limit is exceeded.LargestLimitedMemoryCache
: The largest bitmap is deleted when the cache size limit is exceeded.LimitedAgeMemoryCache
: The Cached object is deleted when its age exceeds defined value.WeakMemoryCache
: A memory cache with only weak references to bitmaps.
A simple usage example:
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);
This example uses the default UsingFreqLimitedMemoryCache
.
What actually worked for me was setting ResponseCache on my Main class:
try {
File httpCacheDir = new File(getApplicationContext().getCacheDir(), "http");
long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
HttpResponseCache.install(httpCacheDir, httpCacheSize);
} catch (IOException e) { }
and
connection.setUseCaches(true);
when downloading bitmap.
http://practicaldroid.blogspot.com/2013/01/utilizing-http-response-cache.html
Google's libs-for-android has a nice libraries for managing image and file cache.
http://code.google.com/p/libs-for-android/
I had been wrestling with this for some time; the answers using SoftReferences would lose their data too quickly. The answers that suggest instantiating a RequestCache were too messy, plus I could never find a full example.
But ImageDownloader.java works wonderfully for me. It uses a HashMap until the capacity is reached or until the purge timeout occurs, then things get moved to a SoftReference, thereby using the best of both worlds.
I suggest IGNITION this is even better than Droid fu
https://github.com/kaeppler/ignition
https://github.com/kaeppler/ignition/wiki/Sample-applications
Even later answer, but I wrote an Android Image Manager that handles caching transparently (memory and disk). The code is on Github https://github.com/felipecsl/Android-ImageManager
Late answer, but I figured I should add a link to my site because I have written a tutorial how to make an image cache for android:
http://squarewolf.nl/2010/11/android-image-cache/
Update: the page has been taken offline as the source was outdated. I join @elenasys in her advice to use Ignition.
So to all the people who stumble upon this question and haven't found a solution: hope you enjoy! =D
참고URL : https://stackoverflow.com/questions/1945201/android-image-caching
'Programing' 카테고리의 다른 글
UnicodeEncodeError : 'charmap'코덱이 문자를 인코딩 할 수 없습니다 (0) | 2020.06.20 |
---|---|
Spring Data JPA에 커스텀 메소드를 추가하는 방법 (0) | 2020.06.20 |
스칼라에서 환경 변수를 읽는 방법 (0) | 2020.06.20 |
두 개의 두 숫자 사이의 난수 (0) | 2020.06.20 |
UIPanGestureRecognizer-세로 또는 가로 만 (0) | 2020.06.20 |