Jawaban:
Dan sekarang lucunya: gunakan cache sistem.
URL url = new URL(strUrl);
URLConnection connection = url.openConnection();
connection.setUseCaches(true);
Object response = connection.getContent();
if (response instanceof Bitmap) {
Bitmap bitmap = (Bitmap)response;
}
Menyediakan memori dan cache flash-rom, dibagikan dengan browser.
Grr. Saya berharap seseorang mengatakan kepada saya bahwa sebelum saya menulis cache manager saya sendiri.
connection.getContent()
selalu mengembalikan InputStream untuk saya, apa yang saya lakukan salah?
Bitmap response = BitmapFactory.decodeStream((InputStream)connection.getContent());
Mengenai connection.setUseCaches
solusi elegan di atas: sayangnya, itu tidak akan bekerja tanpa usaha tambahan. Anda harus menginstal ResponseCache
menggunakan ResponseCache.setDefault
. Kalau tidak, HttpURLConnection
diam-diam akan mengabaikan setUseCaches(true)
bit.
Lihat komentar di bagian atas FileResponseCache.java
untuk detail:
(Saya akan memposting ini dalam komentar, tetapi saya tampaknya tidak memiliki cukup karma SO.)
HttpResponseCache
, Anda mungkin menemukan HttpResponseCache.getHitCount()
0. kembali. Saya tidak yakin tapi saya pikir itu karena server web yang Anda minta tidak menggunakan header caching dalam kasus itu. Untuk membuat caching berfungsi, gunakan connection.addRequestProperty("Cache-Control", "max-stale=" + MAX_STALE_CACHE);
.
.getContent()
metode karena 304 tanggapan tidak memiliki badan respons terkait dengan standar RFC.
Konversikan ke dalam Bitmap dan kemudian simpan dalam Koleksi (HashMap, Daftar, dll.) Atau Anda dapat menuliskannya di SDcard.
Saat menyimpannya di ruang aplikasi menggunakan pendekatan pertama, Anda mungkin ingin membungkusnya di sekitar java.lang.ref.SoftReference khusus jika jumlahnya besar (sehingga mereka dikumpulkan saat krisis). Ini bisa terjadi Reload sekalipun.
HashMap<String,SoftReference<Bitmap>> imageCache =
new HashMap<String,SoftReference<Bitmap>>();
menulisnya di SDcard tidak akan membutuhkan Reload; hanya izin pengguna.
Uri
referensi path yang bisa Anda sampaikan ImageView
dan tampilan kustom lainnya. Karena setiap kali Anda compress
, Anda akan kehilangan kualitas. Tentu saja ini berlaku untuk algoritma lossy saja. Metode ini juga akan memungkinkan Anda untuk bahkan menyimpan hash file dan menggunakannya saat Anda meminta file dari server melalui If-None-Match
dan ETag
header.
Gunakan LruCache
untuk menyimpan gambar dengan efisien. Anda dapat membaca tentang LruCache
dari situs Pengembang Android
Saya telah menggunakan solusi di bawah ini untuk unduhan dan caching gambar di Android. Anda dapat mengikuti langkah-langkah di bawah ini:
LANGKAH 1:
buat Kelas Bernama ImagesCache
. Saya sudah menggunakanSingleton 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();
}
}
}
LANGKAH 2:
buat kelas lain bernama DownloadImageTask yang digunakan jika bitmap tidak tersedia di cache, ia akan mengunduhnya dari sini:
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;
}
LANGKAH 3: Penggunaan dari Anda Activity
atauAdapter
Catatan: Jika Anda ingin memuat gambar dari url dari Activity
Kelas. Gunakan Konstruktor kedua DownloadImageTask
, tetapi jika Anda ingin menampilkan gambar dari Adapter
gunakan Konstruktor pertama DownloadImageTask
(misalnya Anda memiliki gambar ListView
dan Anda mengatur gambar dari 'Adaptor')
PENGGUNAAN DARI AKTIVITAS:
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);
}
PENGGUNAAN DARI 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);
}
catatan:
cache.initializeCache()
Anda dapat menggunakan pernyataan ini di Aktivitas pertama aplikasi Anda. Setelah Anda menginisialisasi cache, Anda tidak perlu menginisialisasi setiap kali jika Anda menggunakan ImagesCache
instance.
Saya tidak pernah pandai menjelaskan hal-hal tetapi saya harap ini akan membantu para pemula bahwa cara menggunakan cache LruCache
dan penggunaannya :)
EDIT:
Sekarang, ada beberapa perpustakaan terkenal yang dikenal Picasso
dan Glide
dapat digunakan untuk memuat gambar dengan sangat efisien di aplikasi android. Coba pustaka Picasso yang sangat sederhana dan bermanfaat ini untuk Android dan Glide For Android . Anda tidak perlu khawatir tentang gambar cache.
Picasso memungkinkan pemuatan gambar tanpa repot di aplikasi Anda — sering kali dalam satu baris kode!
Glide, seperti halnya Picasso, dapat memuat dan menampilkan gambar dari banyak sumber, sambil juga menjaga caching dan menjaga dampak memori rendah ketika melakukan manipulasi gambar. Ini telah digunakan oleh aplikasi Google resmi (seperti aplikasi untuk Google I / O 2015) dan sama populernya dengan Picasso. Dalam seri ini, kita akan mengeksplorasi perbedaan dan kelebihan Glide dibandingkan Picasso.
Anda juga dapat mengunjungi blog untuk perbedaan antara Glide dan Picasso
if(cache == null)
yang memecahkan masalah saya! :)
Untuk mengunduh gambar dan menyimpannya ke kartu memori, Anda dapat melakukannya seperti ini.
//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));
Jangan lupa untuk menambahkan izin Internet ke manifes Anda:
<uses-permission android:name="android.permission.INTERNET" />
Saya akan mempertimbangkan untuk menggunakan cache gambar droidfu. Ini mengimplementasikan cache gambar berbasis di memori dan berbasis disk. Anda juga mendapatkan WebImageView yang memanfaatkan perpustakaan ImageCache.
Berikut adalah deskripsi lengkap droidfu dan WebImageView: http://brainflush.wordpress.com/2009/11/23/droid-fu-part-2-webimageview-and-webgalleryadapter/
Saya sudah mencoba SoftReferences, mereka terlalu agresif direklamasi di android sehingga saya merasa tidak ada gunanya menggunakannya
SoftReference
s. Mereka merekomendasikan menggunakan mereka LruCache
sebagai gantinya.
Seperti yang disarankan Thunder Rabbit, ImageDownloader adalah yang terbaik untuk pekerjaan itu. Saya juga menemukan sedikit variasi kelas di:
http://theandroidcoder.com/utilities/android-image-download-and-caching/
Perbedaan utama antara keduanya adalah bahwa ImageDownloader menggunakan sistem caching Android, dan yang dimodifikasi menggunakan penyimpanan internal dan eksternal sebagai caching, menjaga gambar dalam cache tanpa batas waktu atau sampai pengguna menghapusnya secara manual. Penulis juga menyebutkan kompatibilitas Android 2.1.
Ini tangkapan yang bagus oleh Joe. Contoh kode di atas memiliki dua masalah - satu - objek respons bukan merupakan contoh Bitmap (ketika URL saya mereferensikan jpg, seperti http: \ website.com \ image.jpg, ini merupakan
org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl $ LimitedInputStream).
Kedua, seperti yang ditunjukkan oleh Joe, tidak ada cache yang terjadi tanpa cache respons dikonfigurasikan. Pengembang Android dibiarkan menggulung cache mereka sendiri. Berikut ini contoh untuk melakukannya, tetapi itu hanya cache dalam memori, yang sebenarnya bukan solusi lengkap.
http://codebycoffee.com/2010/06/29/using-responsecache-in-an-android-app/
API caching URLConnection dijelaskan di sini:
http://download.oracle.com/javase/6/docs/technotes/guides/net/http-cache.html
Saya masih berpikir ini adalah solusi OK untuk menempuh rute ini - tetapi Anda masih harus menulis cache. Kedengarannya menyenangkan, tapi saya lebih suka menulis fitur.
Ada entri khusus di bagian pelatihan resmi Android tentang ini: http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
Bagian ini cukup baru, tidak ada di sana ketika pertanyaan diajukan.
Solusi yang disarankan adalah menggunakan LruCache. Kelas itu diperkenalkan di Honeycomb, tetapi juga termasuk di perpustakaan kompatibilitas.
Anda dapat menginisialisasi LruCache dengan mengatur jumlah atau entri maksimum dan secara otomatis Anda akan mengurutkannya dan membersihkannya dari yang kurang digunakan saat Anda melampaui batas. Selain itu digunakan sebagai Peta normal.
Kode sampel dari halaman resmi:
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 sebelumnya adalah alternatif yang baik, tetapi tidak lagi, mengutip dari halaman resmi:
Catatan: Di masa lalu, implementasi cache memori yang populer adalah cache bitmap SoftReference atau WeakReference, namun ini tidak disarankan. Mulai dari Android 2.3 (API Level 9) pemulung lebih agresif dengan mengumpulkan referensi lunak / lemah yang membuatnya tidak efektif. Selain itu, sebelum Android 3.0 (API Level 11), data dukungan bitmap disimpan dalam memori asli yang tidak dirilis dengan cara yang dapat diprediksi, berpotensi menyebabkan aplikasi untuk secara singkat melebihi batas memori dan crash.
Pertimbangkan untuk menggunakan pustaka Universal Image Loader oleh Sergey Tarasevich . Itu datang dengan:
Universal Image Loader memungkinkan manajemen cache terperinci untuk gambar yang diunduh, dengan konfigurasi cache berikut:
UsingFreqLimitedMemoryCache
: Bitmap yang paling jarang digunakan dihapus ketika batas ukuran cache terlampaui.LRULimitedMemoryCache
: Bitmap yang paling baru digunakan dihapus ketika batas ukuran cache terlampaui.FIFOLimitedMemoryCache
: Aturan FIFO digunakan untuk penghapusan ketika batas ukuran cache terlampaui.LargestLimitedMemoryCache
: Bitmap terbesar dihapus ketika batas ukuran cache terlampaui.LimitedAgeMemoryCache
: Objek dalam cache dihapus ketika usianya melebihi nilai yang ditentukan .WeakMemoryCache
: Cache memori dengan hanya referensi lemah ke bitmap.Contoh penggunaan sederhana:
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);
Contoh ini menggunakan default UsingFreqLimitedMemoryCache
.
Apa yang sebenarnya berhasil bagi saya adalah mengatur ResponseCache di kelas Utama saya:
try {
File httpCacheDir = new File(getApplicationContext().getCacheDir(), "http");
long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
HttpResponseCache.install(httpCacheDir, httpCacheSize);
} catch (IOException e) { }
dan
connection.setUseCaches(true);
saat mengunduh bitmap.
http://practicaldroid.blogspot.com/2013/01/utilizing-http-response-cache.html
Google libs-for-android memiliki perpustakaan yang bagus untuk mengelola cache gambar dan file.
Saya telah bergulat dengan ini selama beberapa waktu; jawaban yang menggunakan SoftReferences akan kehilangan data terlalu cepat. Jawaban yang menyarankan instantiating RequestCache terlalu berantakan, ditambah saya tidak pernah bisa menemukan contoh lengkap.
Tetapi ImageDownloader.java bekerja sangat baik untuk saya. Ia menggunakan HashMap sampai kapasitas tercapai atau sampai waktu pembersihan habis, maka semuanya dipindahkan ke SoftReference, dengan demikian menggunakan yang terbaik dari kedua dunia.
Saya menyarankan IGNITION ini bahkan lebih baik daripada Droid fu
https://github.com/kaeppler/ignition
https://github.com/kaeppler/ignition/wiki/Sample-applications
Bahkan kemudian menjawab, tetapi saya menulis Android Image Manager yang menangani caching secara transparan (memori dan disk). Kode ini ada di Github https://github.com/felipecsl/Android-ImageManager
Akhir jawaban, tapi kupikir aku harus menambahkan link ke situs saya karena saya telah menulis tutorial bagaimana membuat cache gambar untuk android: http://squarewolf.nl/2010/11/android-image-cache/ Update: yang halaman telah diambil offline karena sumbernya sudah usang. Saya bergabung dengan @elenasys dalam sarannya untuk menggunakan Ignition .
Jadi untuk semua orang yang menemukan pertanyaan ini dan belum menemukan solusi: semoga Anda menikmati! = D
Jawaban telat tapi saya pikir perpustakaan ini akan banyak membantu dengan caching gambar: https://github.com/crypticminds/ColdStorage .
Cukup beri catatan pada ImageView dengan @LoadCache (R.id.id_of_my_image_view, "URL_to_downlaod_image_from) dan itu akan menangani pengunduhan gambar dan memuatnya ke dalam tampilan gambar. Anda juga dapat menentukan gambar placeholder dan memuat animasi.
Dokumentasi rinci anotasi ada di sini: - https://github.com/crypticminds/ColdStorage/wiki/@LoadImage-annotation