Necesito descargar varias imágenes al directorio para poder acceder al contenido sin conexión

Obtengo algunos datos JSON que contienen algunos elementos de menú de alimentos

Tenga en cuenta: esto es sólo una muestra, hay más de 2 imágenes a veces y muchos más elementos de menú en la matriz!

{ "menu": [ { "url": "/api/v1/menu/1", "name": "Best Food", "description": "really nice food", "opening_time": "every day from 9am to 6pm", "contact_email": "[email protected]", "tel_number": "+54 911 3429 5762", "website": "http://bestfood.com", "images": [ { "url": "https://blahblah/image1.jpg" }, { "url": "https://blahblah/image2.jpg" } ] }, ] } 

Cada elemento tiene información y una matriz de URL de imagen.

Estoy utilizando la biblioteca de imágenes Glide para procesar estas imágenes y Retrofit 2.0 para descargar los datos JSON desde el punto final. Todo está bien en este punto.

Sin embargo, necesito almacenar estos datos descargados para acceso sin conexión.

Actualmente, estoy usando ORM Lite en mis modelos existentes para almacenar todos los datos JSON en una base de datos. Esta parte está bien.

Sin embargo, en mi base de datos sólo almacenar las URL de la imagen como me dijeron que no es un buen enfoque para almacenar imágenes (como blob) en la base de datos.

Así que hay una sección en mi aplicación para ver el menú guardado con una opción para descargarlo para el acceso sin conexión si el usuario elige.

Vale la pena mencionar en este punto, que ya tengo la información de menú en bruto en la base de datos porque el usuario tendría que ver el menú en primer lugar para obtenerlo en DB.

Pero el problema son las imágenes.

Aquí es donde no sé cómo proceder, pero enumerar las soluciones y los problemas que estoy pensando y esperaba que la gente podría aconsejarme sobre cuál es el mejor curso de acción es.

  1. Utilice un servicio para descargar las imágenes. Esto me parece obligatorio porque no sé cuántas imágenes habrá, y quiero que la descarga continúe aunque el usuario abandone la aplicación

  2. Glide tiene una opción de descarga sólo para las imágenes y puede configurar dónde se encuentra su caché (privado interno o público externo) como he leído aquí y aquí . El problema es que no me siento cómodo con la configuración del tamaño de la caché como no sé lo que se requiere. Me gustaría establecer ilimitado.

  3. Tengo que ser capaz de eliminar los datos del menú guardado, especialmente si su guardado en el directorio público externo, ya que no se elimina cuando la aplicación se elimina, etc, o si el usuario elige eliminar un menú guardado dentro de la aplicación. Yo estaba pensando que podría almacenar la imagen del archivo URIs o la ubicación de todo el menú guardado en la base de datos para esto, pero no estoy seguro de si esto es una buena manera

  4. He leído en diferentes fuentes y respuestas que en este caso de uso de sólo caché de imágenes a la tarjeta SD, etc que debería utilizar específicamente una biblioteca de red para hacerlo para evitar la asignación de un mapa de bits para amontonar la memoria. Estoy utilizando HTTP OK en mi aplicación en este momento.

Estoy utilizando ormlite para almacenar objetos con urls también, tengo una sincronización después de la pantalla de "inicio de sesión" en mi aplicación, en mi experiencia Realmente recomiendo esta biblioteca https://github.com/thest1/LazyList

Es muy sencillo:

 ImageLoader imageLoader=new ImageLoader(context); imageLoader.DisplayImage(url, imageView); 

Esta biblioteca guarda la imagen usando la url en el sd externo con una configuración básica y sencilla sobre los problemas de memoria, por lo que si realmente tiene dos o más elementos con la misma url esta biblioteca funciona perfectamente, la url y imageView son los parámetros, La imagen no está en el teléfono comienza una nueva tarea y poner la imagen en la vista cuando la descarga es terminar, y btw esta biblioteca también guarda las imágenes codificadas, por lo que estas imágenes no aparecen en la galería. En realidad solo necesita estos archivos para implementar la biblioteca: https://github.com/thest1/LazyList/tree/master/src/com/fedorvlasov/lazylist

Si desea manipular algunos archivos, puede cambiar el nombre de la carpeta en la clase FileCache:

  public FileCache(Context context){ //Find the dir to save cached images ... cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),"LazyList"); ... } 

Donde "LazyList" es el nombre de la carpeta, y ellos se pueden borrar, mover, etc. Eliminar ejemplo:

  /** * This method delete a file if exist */ public static void deleteFile(File file){ if(file!=null && file.exists()) { file.delete(); } } 

Ahora aprendí más sobre el caché de memoria y la asignación de un mapa de bits a la memoria del montón, por primera vez manipulación de imágenes en línea y fuera de línea, recomiendo esta biblioteca, también cuando se aprende más sobre ello, puede implementar y editar la biblioteca a sus necesidades .

1: Utilice un IntentService para hacer sus descargas.

http://developer.android.com/reference/android/app/IntentService.html

2: Configure su IntentService usando AlarmManager para que se ejecute incluso si la aplicación no se está ejecutando. Usted se registra con el AlarmManager

http://developer.android.com/reference/android/app/AlarmManager.html

Hay una variedad de maneras que usted puede tener el AlarmManager comenzar su intención.

Por ejemplo: // Registrar la primera ejecución y después el intervalo para los ciclos repetidos. AlarmManager.setInexactRepeating (AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime () + DEFAULT_INITIAL_RUN, DEFAULT_RUN_INTERVAL, pi);

3: Almacenamiento de datos Existen varias opciones aquí dependiendo de la forma pública en la que desea que sus imágenes / datos sean.

http://developer.android.com/reference/android/os/Environment.html

Ejemplo: Archivo de almacenamiento público externo dirBackup = Environment.getExternalStoragePublicDirectory ("YourDirectory");

4: Descarga

Su opción aquí. Puedes usar cualquier cosa desde tu API actual a una URLConnection básica.

Usted puede querer mirar:

 http://developer.android.com/reference/android/app/DownloadManager.html 

Además, vea los permisos que necesitará agregar y

Espero que esto le señala en una dirección útil.

Pruebe esta biblioteca para gestionar la carga de imágenes.

Utilice un servicio para descargar las imágenes. Esto me parece obligatorio porque no sé cuántas imágenes habrá, y quiero que la descarga continúe aunque el usuario abandone la aplicación

Toda la descarga se realiza en los subprocesos de trabajo para que esté viva mientras el proceso de aplicación está vivo. Puede aparecer un problema: la aplicación muere mientras la carga está en curso. Para solucionar este problema, sugiero utilizar AlarmManager en combinación con Service . Configurarlo para iniciar por temporizador, compruebe la base de datos o la caché UIL para que los archivos de imagen no se carguen y comience a cargar de nuevo.

Glide tiene una opción de descarga sólo para las imágenes y puede configurar dónde se encuentra su caché (privado interno o público externo) como leo aquí y aquí. El problema es que no me siento cómodo con la configuración del tamaño de la caché como no sé lo que se requiere. Me gustaría establecer ilimitado.

UIL tiene varias implementaciones de caché de disco fuera de la caja incluyendo ilimitada. También proporciona interfaz de caché para que pueda implementar su propio.

Tengo que ser capaz de eliminar los datos del menú guardado, especialmente si su guardado en el directorio público externo, ya que no se elimina cuando la aplicación se elimina, etc, o si el usuario elige eliminar un menú guardado dentro de la aplicación. Yo estaba pensando que podría almacenar la imagen del archivo URIs o la ubicación de todo el menú guardado en la base de datos para esto, pero no estoy seguro de si esto es una buena manera

UIL genera un nombre de archivo único para cada archivo cargado mediante el vínculo de archivo proporcionado. Puede eliminar cualquier imagen cargada o cancelar cualquier descarga mediante el enlace de su JSON.

He leído en diferentes fuentes y respuestas que en este caso de uso de sólo caché de imágenes a la tarjeta SD, etc que debería utilizar específicamente una biblioteca de red para hacerlo para evitar la asignación de un mapa de bits para amontonar la memoria. Estoy utilizando HTTP OK en mi aplicación en este momento.

UIL lo hace bien. Gestiona la memoria con mucha precisión también le proporcionan varias opciones para la configuración de gestión de memoria. Por ejemplo, puede elegir entre varias implementaciones de caché de memoria fuera de la caja.

En conclusión le sugiero que visite el enlace anterior y lea la documentación de la biblioteca / descripción por usted mismo. Es muy flexible y contatins muchas características útiles.

El uso de un servicio puede ser una buena opción si desea que las descargas continúen aunque el usuario salga. Las imágenes almacenadas en los directorios creados mediante getExternalStorageDirectory() se eliminan automáticamente cuando se desinstala la aplicación. Además, puede comprobar si la memoria interna es lo suficientemente grande como para almacenar imágenes. Si utiliza este método, estas imágenes se eliminarán tras la desinstalación de la aplicación.

Yo uso esta clase cuando la descarga de imágenes, se almacena en caché las imágenes, la próxima vez que va a descargar ellos sólo se cargará desde la memoria externa, que gestiona la memoria caché para usted también, así que no tendrá que preocuparse por la configuración de la caché a limitada o ilimitada, Bastante eficiente y rápido.

 public class ImageLoader { MemoryCache memoryCache = new MemoryCache(); FileCache fileCache; private Map<ImageView, String> imageViews = Collections .synchronizedMap(new WeakHashMap<ImageView, String>()); ExecutorService executorService; // Handler to display images in UI thread Handler handler = new Handler(); public ImageLoader(Context context) { fileCache = new FileCache(context); executorService = Executors.newFixedThreadPool(5); } final int stub_id = R.drawable.placeholder; public void DisplayImage(String url, ImageView imageView) { imageViews.put(imageView, url); Bitmap bitmap = memoryCache.get(url); if (bitmap != null) imageView.setImageBitmap(bitmap); else { queuePhoto(url, imageView); imageView.setImageResource(stub_id); } } private void queuePhoto(String url, ImageView imageView) { PhotoToLoad p = new PhotoToLoad(url, imageView); executorService.submit(new PhotosLoader(p)); } private Bitmap getBitmap(String url) { File f = fileCache.getFile(url); Bitmap b = decodeFile(f); if (b != null) return b; // Download Images from the Internet try { Bitmap bitmap = null; URL imageUrl = new URL(url); HttpURLConnection conn = (HttpURLConnection) imageUrl .openConnection(); conn.setConnectTimeout(30000); conn.setReadTimeout(30000); conn.setInstanceFollowRedirects(true); InputStream is = conn.getInputStream(); OutputStream os = new FileOutputStream(f); Utils.CopyStream(is, os); os.close(); conn.disconnect(); bitmap = decodeFile(f); return bitmap; } catch (Throwable ex) { ex.printStackTrace(); if (ex instanceof OutOfMemoryError) memoryCache.clear(); return null; } } // Decodes image and scales it to reduce memory consumption private Bitmap decodeFile(File f) { try { // Decode image size BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; FileInputStream stream1 = new FileInputStream(f); BitmapFactory.decodeStream(stream1, null, o); stream1.close(); // Find the correct scale value. It should be the power of 2. // Recommended Size 512 final int REQUIRED_SIZE = 70; int width_tmp = o.outWidth, height_tmp = o.outHeight; int scale = 1; while (true) { if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE) break; width_tmp /= 2; height_tmp /= 2; scale *= 2; } // Decode with inSampleSize BitmapFactory.Options o2 = new BitmapFactory.Options(); o2.inSampleSize = scale; FileInputStream stream2 = new FileInputStream(f); Bitmap bitmap = BitmapFactory.decodeStream(stream2, null, o2); stream2.close(); return bitmap; } catch (FileNotFoundException e) { } catch (IOException e) { e.printStackTrace(); } return null; } // Task for the queue private class PhotoToLoad { public String url; public ImageView imageView; public PhotoToLoad(String u, ImageView i) { url = u; imageView = i; } } class PhotosLoader implements Runnable { PhotoToLoad photoToLoad; PhotosLoader(PhotoToLoad photoToLoad) { this.photoToLoad = photoToLoad; } @Override public void run() { try { if (imageViewReused(photoToLoad)) return; Bitmap bmp = getBitmap(photoToLoad.url); memoryCache.put(photoToLoad.url, bmp); if (imageViewReused(photoToLoad)) return; BitmapDisplayer bd = new BitmapDisplayer(bmp, photoToLoad); handler.post(bd); } catch (Throwable th) { th.printStackTrace(); } } } boolean imageViewReused(PhotoToLoad photoToLoad) { String tag = imageViews.get(photoToLoad.imageView); if (tag == null || !tag.equals(photoToLoad.url)) return true; return false; } // Used to display bitmap in the UI thread class BitmapDisplayer implements Runnable { Bitmap bitmap; PhotoToLoad photoToLoad; public BitmapDisplayer(Bitmap b, PhotoToLoad p) { bitmap = b; photoToLoad = p; } public void run() { if (imageViewReused(photoToLoad)) return; if (bitmap != null) photoToLoad.imageView.setImageBitmap(bitmap); else photoToLoad.imageView.setImageResource(stub_id); } } public void clearCache() { memoryCache.clear(); fileCache.clear(); } 

}

Para usarlo Simplemente crea una instancia de él como

  ImageLoader Imageloaer = new ImageLoader(getBaseContext()); Imageloaer.DisplayImage(imageUrl, imageView); 

Usted debe tratar de descargar con esto,

  class DownloadFile extends AsyncTask<String,Integer,Long> { ProgressDialog mProgressDialog = new ProgressDialog(MainActivity.this);// Change Mainactivity.this with your activity name. String strFolderName; @Override protected void onPreExecute() { super.onPreExecute(); mProgressDialog.setMessage("Downloading Image ..."); mProgressDialog.setIndeterminate(false); mProgressDialog.setMax(100); mProgressDialog.setCancelable(false); mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); mProgressDialog.show(); } @Override protected Long doInBackground(String... aurl) { int count; try { URL url = new URL((String) aurl[0]); URLConnection conexion = url.openConnection(); conexion.connect(); String targetFileName="downloadedimage.jpg";//Change name and subname int lenghtOfFile = conexion.getContentLength(); String PATH = Environment.getExternalStorageDirectory()+"/myImage/"; File folder = new File(PATH); if(!folder.exists()){ folder.mkdir();//If there is no folder it will be created. } InputStream input = new BufferedInputStream(url.openStream()); OutputStream output = new FileOutputStream(PATH+targetFileName); byte data[] = new byte[1024]; long total = 0; while ((count = input.read(data)) != -1) { total += count; publishProgress ((int)(total*100/lenghtOfFile)); output.write(data, 0, count); } output.flush(); output.close(); input.close(); } catch (Exception e) {} return null; } protected void onProgressUpdate(Integer... progress) { mProgressDialog.setProgress(progress[0]); if(mProgressDialog.getProgress()==mProgressDialog.getMax()){ mProgressDialog.dismiss(); Toast.makeText(getApplicationContext(), "Download Completed !", Toast.LENGTH_LONG).show(); } } protected void onPostExecute(String result) { } } 

Este código le permitirá descargar todo el url de imágenes,

  new DownloadFile().execute("/images//w4kCo.jpg"); 

…..

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

Cambie el nombre de la carpeta como usted deseó e intente fijar estas imágenes al mapa de bits de la aplicación y también evitar el giro del error de imágenes usando esto.

Lo importante para pensar aquí es

Thread , Service , File , Json , Context , Receiver y if else

Tal vez no he entendido su pregunta, pero esto no es un gran problema, señor, su programa de su aplicación para trabajar de manera en que su aplicación se inicia cuando la radiodifusión onBootCompleted , a continuación, crear un Thread donde se va a hacer un montón de código de obtención Su archivo json (cuando lo necesite), ya que es una matriz de obtener sus imágenes jsonObject , si es un millón o millones de sólo iterar y utilizar cualquier método para descargarlo, yo diría que utilizar la forma tradicional de descargar su Imágenes para que mejor controlarlo. Con la ayuda de la clase de File que guardar junto con el Context se puede obtener el directorio de caché de su aplicación, que es una memoria interna de guardar allí y crear una columna en su base de datos donde se puede guardar la ruta al archivo en su base de datos como String.

Cuando su aplicación empiece en onPrepareOptionsMenu() compruebe si el directorio de caché de su aplicación está vacío -si no tiene algunos archivos, ahora ya que tiene todos los archivos y su ruta respectiva puede comprobar si existe con File.exist() si no lo hace Necesidad de descargar.

Si necesita ritmo, siempre puede crear nuevos hilos. El Reciever sería el tipo que recibe una notificación cuando el dispositivo se inicia, si no para una gran cantidad de comprobación lógica, para los bucles, el servicio para poder hacer un trabajo largo y tener una forma de comunicarse entre la interfaz de usuario y el hilo de fondo .

Lo siento por el último párrafo que estaba tratando de comprar espacio 🙂

  • Obtener json de HttpResponse
  • ¿Cómo analizar la respuesta de Json en android?
  • Android: crear JSON Array y JSON Object
  • Android - Extraño EscapeUtil.unescapeString falla
  • Parse Json en el estudio android de String
  • Jackson JSON Parser rendimiento
  • Google Plus SignIn / oAuth2 - lanzamiento del lado del servidor TokenResponseException: 401 no autorizado
  • ¿Cómo usar HTTPS y HTTP para analizar datos JSON en Android?
  • Cómo convertir caracteres de indicador a caracteres Unicode Escaped
  • Cómo ignorar un elemento JSON en Android Retrofit
  • Android JSON HttpClient para enviar datos al servidor PHP con HttpResponse
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.