답변:
그리고 펀치 라인 : 시스템 캐시를 사용하십시오.
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.getContent()
항상 나를 위해 InputStream을 반환합니다. 무엇을 잘못하고 있습니까?
Bitmap response = BitmapFactory.decodeStream((InputStream)connection.getContent());
connection.setUseCaches
위 의 우아한 솔루션 과 관련하여 슬프게도 추가 노력 없이는 작동하지 않습니다. ResponseCache
using 을 설치해야합니다 ResponseCache.setDefault
. 그렇지 않으면 비트 HttpURLConnection
를 자동으로 무시합니다 setUseCaches(true)
.
자세한 내용은 상단의 주석을 참조 FileResponseCache.java
하십시오.
(나는 이것을 의견에 게시 할 것이지만 분명히 충분한 업장이 없습니다.)
HttpResponseCache
찾을 수 있습니다. HttpResponseCache.getHitCount()
확실하지 않지만 요청하는 웹 서버가 캐시 헤더를 사용하지 않기 때문이라고 생각합니다. 어쨌든 캐싱이 작동하려면을 사용하십시오 connection.addRequestProperty("Cache-Control", "max-stale=" + MAX_STALE_CACHE);
.
.getContent()
304 응답에 RFC 표준에 의해 응답 본문이 없기 때문에 어떤 이유로 서버에서 304를 반환하면 메소드를 사용할 때 HUC가 중단됩니다 .
비트 맵으로 변환 한 다음 Collection (HashMap, List 등)에 저장하거나 SDcard에 쓸 수 있습니다.
첫 번째 방법을 사용하여 애플리케이션 공간에 저장하는 경우, 숫자가 큰 경우 (위기 동안 가비지 수집 됨) 구체적 으로 java.lang.ref.SoftReference 주위를 랩핑 할 수 있습니다 . 그래도 재로드가 발생할 수 있습니다.
HashMap<String,SoftReference<Bitmap>> imageCache =
new HashMap<String,SoftReference<Bitmap>>();
SDcard에 작성하면 다시로드 할 필요가 없습니다. 단지 사용자 권한.
Uri
전달할 수 있는 경로 참조 ImageView
및 다른 사용자 정의보기 를 얻는 것이 좋습니다 . compress
당신이 때마다 당신은 품질을 잃을 것입니다. 물론 이것은 손실 알고리즘에만 해당됩니다. 이 방법을 사용하면 파일의 해시를 저장하고 다음에 서버 If-None-Match
와 ETag
헤더를 통해 파일을 요청할 때 사용할 수도 있습니다.
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만큼 인기가 있습니다. 이 시리즈에서는 피카소보다 글라이드의 차이점과 장점을 살펴 보겠습니다.
글라이드와 피카소의 차이점에 대한 블로그를 방문 할 수도 있습니다
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의 이미지 캐시 사용을 고려할 것입니다. 인 메모리 및 디스크 기반 이미지 캐시를 모두 구현합니다. ImageCache 라이브러리를 활용하는 WebImageView도 얻을 수 있습니다.
다음은 droidfu 및 WebImageView에 대한 전체 설명입니다. http://brainflush.wordpress.com/2009/11/23/droid-fu-part-2-webimageview-and-webgalleryadapter/
SoftReferences를 사용해 보았습니다 .Android에서 너무 적극적으로 사용하여 사용하지 않아도됩니다.
SoftReference
s 수집에 매우 공격적임을 확인했습니다 . LruCache
대신에 사용하는 것이 좋습니다 .
Thunder Rabbit이 제안한대로 ImageDownloader가이 작업에 가장 적합합니다. 나는 또한 클래스에서 약간의 변형을 발견했다.
http://theandroidcoder.com/utilities/android-image-download-and-caching/
이 둘의 주요 차이점은 ImageDownloader가 Android 캐싱 시스템을 사용하고 수정 된 시스템은 내부 및 외부 저장소를 캐싱으로 사용하여 캐시 된 이미지를 무기한으로 유지하거나 사용자가 수동으로 제거 할 때까지 유지한다는 것입니다. 필자는 Android 2.1 호환성에 대해서도 언급합니다.
이것은 Joe가 잘 잡는 것입니다. 위의 코드 예제에는 두 가지 문제가 있습니다. 하나는 응답 객체가 비트 맵의 인스턴스가 아닙니다 (URL이 http : \ website.com \ image.jpg와 같은 jpg를 참조하는 경우 a)
org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl $ LimitedInputStream).
둘째, Joe가 지적한대로 응답 캐시를 구성하지 않으면 캐싱이 발생하지 않습니다. Android 개발자는 자신의 캐시를 롤업해야합니다. 다음은 그렇게하는 예이지만 메모리에만 캐시되므로 실제로 전체 솔루션은 아닙니다.
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를 사용하는 것입니다. 이 클래스는 Honeycomb에서 소개되었지만 호환성 라이브러리에도 포함되어 있습니다.
최대 수 또는 항목을 설정하여 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는 좋은 대안 이었지만 공식 페이지에서 인용 한 더 이상은 아닙니다.
참고 : 과거에는 널리 사용되는 메모리 캐시 구현은 SoftReference 또는 WeakReference 비트 맵 캐시 였지만 권장되지는 않습니다. Android 2.3 (API 레벨 9)부터 가비지 콜렉터는 소프트 / 약한 참조를 수집하는 데있어 더욱 효과적입니다. 또한 Android 3.0 (API 레벨 11) 이전에는 비트 맵의 백업 데이터가 기본 메모리에 저장되어 예측 가능한 방식으로 릴리스되지 않아 애플리케이션이 메모리 한계를 일시적으로 초과하고 충돌 할 수있었습니다.
사용을 고려 범용 이미지 로더 라이브러리 에 의해 세르게이 Tarasevich . 다음과 함께 제공됩니다.
Universal Image Loader를 사용 하면 다음과 같은 캐시 구성으로 다운로드 이미지에 대한 자세한 캐시 관리 가 가능합니다.
UsingFreqLimitedMemoryCache
: 캐시 크기 제한을 초과하면 가장 적게 사용되는 비트 맵이 삭제됩니다.LRULimitedMemoryCache
: 캐시 크기 제한을 초과하면 가장 최근에 사용한 비트 맵이 삭제됩니다.FIFOLimitedMemoryCache
: 캐시 크기 제한을 초과하면 FIFO 규칙이 삭제에 사용됩니다.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
구글의 안드로이드 라이브러리는 이미지와 파일 캐시를 관리하기위한 훌륭한 라이브러리를 가지고 있습니다.
나는 얼마 동안 이것과 씨름하고 있었다; SoftReferences를 사용하면 응답이 너무 빨리 손실됩니다. RequestCache 인스턴스화를 제안하는 답변이 너무 지저분했으며 완전한 예를 찾을 수 없었습니다.
그러나 ImageDownloader.java 는 훌륭하게 작동합니다. 용량에 도달 할 때까지 또는 퍼지 시간 종료가 발생할 때까지 HashMap을 사용하여 물건이 SoftReference로 이동하여 두 가지 장점 중 가장 좋은 것을 사용합니다.
나는 이것이 Droid fu보다 더 나은 점화를 제안한다.
https://github.com/kaeppler/ignition
https://github.com/kaeppler/ignition/wiki/Sample-applications
나중에 대답하지만 캐싱을 투명하게 처리하는 Android 이미지 관리자 (메모리 및 디스크)를 작성했습니다. 코드는 Github https://github.com/felipecsl/Android-ImageManager에 있습니다.
: 늦은 대답,하지만 난 어떻게 안드로이드에 대한 이미지 캐시를 만드는 튜토리얼 작성한 때문에 나는 내 사이트에 대한 링크를 추가해야합니다 생각 http://squarewolf.nl/2010/11/android-image-cache/ 업데이트 : 소스가 오래되어 페이지가 오프라인 상태가되었습니다. 나는 Ignition 사용에 대한 조언으로 @elenasys에 합류했습니다 .
따라서이 질문에 걸려 넘어져 해결책을 찾지 못한 모든 사람들에게 당신이 즐기기를 바랍니다! = D
늦은 답변이지만이 라이브러리는 이미지 캐싱에 많은 도움이 될 것이라고 생각합니다 : https://github.com/crypticminds/ColdStorage .
@LoadCache (R.id.id_of_my_image_view, "URL_to_downlaod_image_from)를 사용하여 ImageView에 주석을 달기 만하면 이미지를 다운로드하여 이미지보기에로드하고 자리 표시 자 이미지를 지정하고 애니메이션을로드 할 수도 있습니다.
주석에 대한 자세한 문서는 여기에 있습니다 : -https : //github.com/crypticminds/ColdStorage/wiki/@LoadImage-annotation