Las imágenes que no se almacenan en caché localmente (con Universal Image Loader) – tiempos de carga lenta de la imagen

Descripción del problema: Estoy creando una lista desplazable de artículos con miniaturas que está poblada por mi base de datos SQLite. En general, está "trabajando" excepto ser lento:

Las imágenes se cargan muy lentamente … Pensé que usar el " Universal Image Loader " almacenaba en caché las imágenes en el dispositivo, y eso haría que aparecieran para desplazarse a la vista si ya las habías visto (o al menos cerca de eso ). Pero – cuando arrastra hacia arriba / abajo, ninguna de las imágenes está allí, luego 3-5 segundos más tarde, las imágenes empiezan a aparecer (como si se vuelva a descargar)

Estoy cambiando la visibilidad de los cuadros en miniatura sobre la marcha, pero que funciona perfectamente – no parecen cambiar – que sólo se desplaza en la vista o no, sin parpadear o nada. (Pero luego las imágenes no aparecen durante unos segundos).

He probado mediante la eliminación de mi script php después de desplazamiento alrededor … cuando vuelvo a la zona anterior, las imágenes no se muestran – lo que me hace suponer que está cargando desde mi script PHP CADA vez.

Pero de acuerdo con los documentos : "UsingFreqLimitedMemoryCache (El bitmap menos utilizado se elimina cuando se supera el límite de tamaño de la caché) – Utilizado por defecto"

Detalles:

En mi ArticleEntryAdapter.js tengo:

 @Override public View getView(final int position, final View convertView, final ViewGroup parent) { // We need to get the best view (re-used if possible) and then // retrieve its corresponding ViewHolder, which optimizes lookup efficiency final View view = getWorkingView(convertView); final ViewHolder viewHolder = getViewHolder(view); final Article article = getItem(position); // Set the title viewHolder.titleView.setText(article.title); //Set the subtitle (subhead) or description if(article.subtitle != null) { viewHolder.subTitleView.setText(article.subtitle); } else if(article.description != null) { viewHolder.subTitleView.setText(article.description); } ImageLoader imageLoader = ImageLoader.getInstance(); imageLoader.displayImage("", viewHolder.thumbView); //clears previous one if(article.filepath != null && article.filepath.length() != 0) { imageLoader.displayImage( "http://img.sltdb.com/processes/resize.php?image=" + article.filepath + "&size=100&quality=70", viewHolder.thumbView ); viewHolder.thumbView.setVisibility(View.VISIBLE); } else { viewHolder.thumbView.setVisibility(View.GONE); } return view; } 

En cuanto a las imágenes que son incorrectas – no es a menudo, pero a veces durante el desplazamiento, voy a ver 2 de la misma imagen, y cuando miro a los artículos, no están en absoluto relacionados (es decir, ninguna posibilidad de tener realmente la La misma imagen) Así que – me desplaza lejos de ella, y de nuevo, y ya no es la imagen incorrecta.

NOTA: Soy nuevo en Java / Android – probablemente ya lo notaste.

Más código por comentario-solicitud:

 private View getWorkingView(final View convertView) { // The workingView is basically just the convertView re-used if possible // or inflated new if not possible View workingView = null; if(null == convertView) { final Context context = getContext(); final LayoutInflater inflater = (LayoutInflater)context.getSystemService (Context.LAYOUT_INFLATER_SERVICE); workingView = inflater.inflate(articleItemLayoutResource, null); } else { workingView = convertView; } return workingView; } 

ACTUALIZACIÓN: Mi archivo de manifiesto tiene:

 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 

Pero la carpeta caché que encontré está completamente vacía:

 mnt -sdcard -Android -data -com.mysite.news -cache -uil-images 

Tenía problemas similares con imágenes en la vista de lista. Posiblemente esta respuesta corregirá su problema de imagen incorrecta.

Acabo de descargar el proyecto de ejemplo con UniversalImageLoader y muestra el mismo comportamiento que está describiendo.

Algunas notas tan lejos de mirar a través del código fuente.

 public static final int DEFAULT_THREAD_POOL_SIZE = 3; public static final int DEFAULT_THREAD_PRIORITY = Thread.NORM_PRIORITY - 1; public static final int DEFAULT_MEMORY_CACHE_SIZE = 2 * 1024 * 1024; // bytes 

Esto dice que en cualquier momento habrá tres subprocesos de descarga y un máximo de 2MB de imágenes. ¿Qué tamaño tienen las imágenes que está descargando? También se está caché en el disco? Si es así, será lento.

Para configurar algunas de las opciones básicas de ImageLoader necesitará pasar a displayImage:

  DisplayImageOptions options = new DisplayImageOptions.Builder() .showStubImage(R.drawable.stub_image) .cacheInMemory() .cacheOnDisc() .build(); 

También quisiera que pruebes estas opciones:

 ImageLoaderConfiguration imageLoaderConfiguration = new ImageLoaderConfiguration.Builder(this) .enableLogging() .memoryCacheSize(41943040) .discCacheSize(104857600) .threadPoolSize(10) .build(); imageLoader = ImageLoader.getInstance(); imageLoader.init(imageLoaderConfiguration); 

Con mis pruebas, las imágenes están en el disco, pero la carga es aún lenta.

Después de una extensa prueba, determiné que el problema principal es que UniversalImageLoader es lento. En concreto, el ImageLoader y LoadAndDisplayImageTask están manteniendo las obras. I (muy rápidamente) reescribió el LoadAndDisplayImageTask como AsyncTask e inmediatamente se desempeñó mejor. Puede descargar la versión bifurcada del código en GitHub.

Universal Image Loader con AsyncTasks

Una solución alternativa es "RemoteImageView" del proyecto de código abierto de encendido.

http://kaeppler.github.com/ignition-docs/ignition-core/apidocs/com/github/ignition/core/widgets/RemoteImageView.html

Efectivamente, RemoteImageView amplía ImageView y realiza todas las operaciones de búsqueda / almacenamiento en caché para usted detrás de las escenas.

Aunque no necesariamente resuelve el problema que enumeró, podría valer la pena investigar como una solución alternativa.

EDIT: Recomiendo encarecidamente a Picasso si todavía necesitas una solución de imagen remota. He reemplazado RemoteImageView en mis aplicaciones con Picasso: http://square.github.io/picasso/

Sospecho que el resize.php es lento, especialmente si tiene que cambiar el tamaño de páginas grandes, y se reciben varias solicitudes. Y de alguna manera el almacenamiento en caché en imageLoader no se hace.

Primero haría el resto después de la carga de la imagen: subtítulo, descripción y todo. Porque si la carga de la imagen toma demasiado tiempo, hay un efecto más instantáneo, si la descripción y todo el resto aparecen juntos. Por lo general, su orden de las declaraciones está bien.

La respuesta de @CameronLowellPallmer se encarga de las imágenes conmutadas y el almacenamiento en caché.

Esta clase funcionó para mí:

 import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.Map; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.HttpVersion; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.CoreProtocolPNames; import org.apache.http.params.HttpParams; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.util.Log; import android.widget.ImageView; public class ImageDownloader { Map<String,Bitmap> imageCache; public ImageDownloader(){ imageCache = new HashMap<String, Bitmap>(); } //download function public void download(String url, ImageView imageView) { if (cancelPotentialDownload(url, imageView)&&url!=null) { //Caching code right here String filename = String.valueOf(url.hashCode()); File f = new File(getCacheDirectory(imageView.getContext()), filename); // Is the bitmap in our memory cache? Bitmap bitmap = null; bitmap = (Bitmap)imageCache.get(f.getPath()); BitmapFactory.Options bfOptions=new BitmapFactory.Options(); bfOptions.inDither=false; //Disable Dithering mode bfOptions.inPurgeable=true; //Tell to gc that whether it needs free memory, the Bitmap can be cleared bfOptions.inInputShareable=true; //Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future bfOptions.inTempStorage=new byte[32 * 1024]; FileInputStream fs=null; if(bitmap == null){ //bitmap = BitmapFactory.decodeFile(f.getPath(),options); try { fs = new FileInputStream(f); if(fs!=null) bitmap=BitmapFactory.decodeFileDescriptor(fs.getFD(), null, bfOptions); } catch (IOException e) { //TODO do something intelligent e.printStackTrace(); } finally{ if(fs!=null) { try { fs.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } if(bitmap != null){ imageCache.put(f.getPath(), bitmap); } } //No? download it if(bitmap == null){ BitmapDownloaderTask task = new BitmapDownloaderTask(imageView); DownloadedDrawable downloadedDrawable = new DownloadedDrawable(task); imageView.setImageDrawable(downloadedDrawable); task.execute(url); }else{ //Yes? set the image imageView.setImageBitmap(bitmap); } } } //cancel a download (internal only) private static boolean cancelPotentialDownload(String url, ImageView imageView) { BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView); if (bitmapDownloaderTask != null) { String bitmapUrl = bitmapDownloaderTask.url; if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) { bitmapDownloaderTask.cancel(true); } else { // The same URL is already being downloaded. return false; } } return true; } //gets an existing download if one exists for the imageview private static BitmapDownloaderTask getBitmapDownloaderTask(ImageView imageView) { if (imageView != null) { Drawable drawable = imageView.getDrawable(); if (drawable instanceof DownloadedDrawable) { DownloadedDrawable downloadedDrawable = (DownloadedDrawable)drawable; return downloadedDrawable.getBitmapDownloaderTask(); } } return null; } //our caching functions // Find the dir to save cached images public static File getCacheDirectory(Context context){ String sdState = android.os.Environment.getExternalStorageState(); File cacheDir; if (sdState.equals(android.os.Environment.MEDIA_MOUNTED)) { File sdDir = android.os.Environment.getExternalStorageDirectory(); //TODO : Change your diretcory here cacheDir = new File(sdDir,"data/tac/images"); } else cacheDir = context.getCacheDir(); if(!cacheDir.exists()) cacheDir.mkdirs(); return cacheDir; } private void writeFile(Bitmap bmp, File f) { FileOutputStream out = null; try { out = new FileOutputStream(f); bmp.compress(Bitmap.CompressFormat.PNG, 80, out); } catch (Exception e) { e.printStackTrace(); } finally { try { if (out != null ) out.close(); } catch(Exception ex) {} } } /////////////////////// //download asynctask public class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> { private String url; private final WeakReference<ImageView> imageViewReference; public BitmapDownloaderTask(ImageView imageView) { imageViewReference = new WeakReference<ImageView>(imageView); } @Override // Actual download method, run in the task thread protected Bitmap doInBackground(String... params) { // params comes from the execute() call: params[0] is the url. url = (String)params[0]; return downloadBitmap(params[0]); } @Override // Once the image is downloaded, associates it to the imageView protected void onPostExecute(Bitmap bitmap) { if (isCancelled()) { bitmap = null; } if (imageViewReference != null) { ImageView imageView = imageViewReference.get(); BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView); // Change bitmap only if this process is still associated with it if (this == bitmapDownloaderTask) { imageView.setImageBitmap(bitmap); //cache the image String filename = String.valueOf(url.hashCode()); File f = new File(getCacheDirectory(imageView.getContext()), filename); imageCache.put(f.getPath(), bitmap); writeFile(bitmap, f); } } } } static class DownloadedDrawable extends ColorDrawable { private final WeakReference<BitmapDownloaderTask> bitmapDownloaderTaskReference; public DownloadedDrawable(BitmapDownloaderTask bitmapDownloaderTask) { super(Color.BLACK); bitmapDownloaderTaskReference = new WeakReference<BitmapDownloaderTask>(bitmapDownloaderTask); } public BitmapDownloaderTask getBitmapDownloaderTask() { return bitmapDownloaderTaskReference.get(); } } //the actual download code static Bitmap downloadBitmap(String url) { HttpParams params = new BasicHttpParams(); params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1); HttpClient client = new DefaultHttpClient(params); final HttpGet getRequest = new HttpGet(url); try { HttpResponse response = client.execute(getRequest); final int statusCode = response.getStatusLine().getStatusCode(); if (statusCode != HttpStatus.SC_OK) { Log.w("ImageDownloader", "Error " + statusCode + " while retrieving bitmap from " + url); return null; } final HttpEntity entity = response.getEntity(); if (entity != null) { InputStream inputStream = null; try { inputStream = entity.getContent(); final Bitmap bitmap = BitmapFactory.decodeStream(inputStream); return bitmap; } finally { if (inputStream != null) { inputStream.close(); } entity.consumeContent(); } } } catch (Exception e) { // Could provide a more explicit error message for IOException or IllegalStateException getRequest.abort(); Log.w("ImageDownloader", "Error while retrieving bitmap from " + url + e.toString()); } finally { if (client != null) { //client.close(); } } return null; } } 

Ejemplo de uso:

 downloader = new ImageDownloader(); ImageView image_profile =(ImageView) row.findViewById(R.id.image_profile); downloader.download(url, image_profile); 
  • Android no escribirá nueva línea en el archivo de texto
  • Java.lang.NoClassDefFoundError (libgdx)
  • Alternativas a java en android
  • ¿Cómo cambiar el color presionado a otro color del selector dinámicamente?
  • IOException durante la lectura de InputStream
  • ¿Vincula el texto de EditText a una variable?
  • java.lang.IllegalStateException: Necesita usar un tema Theme.AppCompat (o descendente) con esta actividad
  • Actividades cargando xml diseño dinámicamente en android
  • Java.lang.String no se puede convertir a JSONObject desde Android
  • Extraños caracteres de cita alrededor de static java String (en android?)
  • No se puede extraer del fragmento
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.