Guardar Imagen en Memoria Interna Android

Buenos días, en esta entrada veremos como podemos guardar una imagen en nuestra memoria interna del dispositivo que estemos usando.


La funcionalidad de guardar imágenes en nuestro terminal puede ser una buena idea para mantener datos y cargarlos mas tarde. Para ello aprovecharemos el tutorial anterior para descargar las imágenes que podemos encontrar Aquí

Usando el anterior tutorial bajaremos la imagen, la mostraremos, y en el botón que añadiremos a la GUI vamos a llamar al método para guardar nuestra imagen en una carpeta privada.

  • GUI

    Cuando hayamos creado nuestro proyecto Android, modificaremos el XML para que quede así:

    		<RelativeLayout xmlns:android=http://schemas.android.com/apk/res/android
    		    xmlns:tools=http://schemas.android.com/tools
    		    android:layout_width=match_parent
    		    android:layout_height=match_parent
    		    tools:context=.MainActivity>;
    		
    		    ImageView 
    		        android:id=@+id/imagen
    		        android:layout_width=wrap_content
    		        android:layout_height=wrap_content
    		        android:layout_alignParentTop=true;
    		    
    		    Button 
    		        android:id=@+id/btnGuardar
    		        android:layout_width=wrap_content
    		        android:layout_height=wrap_content
    		        android:text=@string/txtGuardar
    		        android:layout_alignParentBottom=true
    		        android:layout_centerHorizontal=true;
    		
    		</RelativeLayout>
    		

    Con este xml lograremos una interfaz gráfica como la siguiente:

    GUI

    Como vemos, es una Interfaz gráfica de lo mas normal y sin ningún tipo de dificultad, para el propósito que queremos no necesitamos mucho mas.

  • Activity

    La activity es prácticamente la misma que en el tutorial anterior, aunque aún no agregaremos la funcionalidad para guardar la imagen:

    		public class MainActivity extends Activity {
    			public static final String URL = http://www.thebiblescholar.com/android_awesome.jpg;
    			
    			private ImageView imgImagen;
    			private Button btnGuardar;
    			
    			@Override
    			protected void onCreate(Bundle savedInstanceState) {
    				super.onCreate(savedInstanceState);
    				setContentView(R.layout.activity_main);
    				
    				imgImagen = (ImageView)findViewById(R.id.imagen);
    				btnGuardar = (Button)findViewById(R.id.btnGuardar);
    				
    				
    				CargaImagenes nuevaTarea = new CargaImagenes();
    				nuevaTarea.execute(URL);
    				
    			}
    			
    			private class CargaImagenes extends AsyncTaskString, Void, Bitmap>{
    				
    				ProgressDialog pDialog;
    		
    				@Override
    				protected void onPreExecute() {
    					// TODO Auto-generated method stub
    					super.onPreExecute();
    					
    					pDialog = new ProgressDialog(MainActivity.this);
    					pDialog.setMessage(Cargando Imagen);
    					pDialog.setCancelable(true);
    					pDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
    					pDialog.show();
    					
    				}
    		
    				@Override
    				protected Bitmap doInBackground(String... params) {
    					// TODO Auto-generated method stub
    					Log.i(doInBackground , Entra en doInBackground);
    					String url = params[0];
    					Bitmap imagen = descargarImagen(url);
    					return imagen;
    				}
    				
    				@Override
    				protected void onPostExecute(Bitmap result) {
    					// TODO Auto-generated method stub
    					super.onPostExecute(result);
    					
    					imgImagen.setImageBitmap(result);
    					pDialog.dismiss();
    				}
    				
    			}
    			
    			private Bitmap descargarImagen (String imageHttpAddress){
    				URL imageUrl = null;
    				Bitmap imagen = null;
    				try{
    					imageUrl = new URL(imageHttpAddress);
    					HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();
    					conn.connect();
    					imagen = BitmapFactory.decodeStream(conn.getInputStream());
    				}catch(IOException ex){
    					ex.printStackTrace();
    				}
    				
    				return imagen;
    			}
    		}
    		
  • Button

    En el elemento Button añadiremos un OnClickListener(), en el cual añadiremos la funcionalidad deseada.

    		btnGuardar.setOnClickListener(new OnClickListener(){
    
    			@Override
    			public void onClick(View v) {
    				// TODO Auto-generated method stub
    				Bitmap imagen = ((BitmapDrawable)imgImagen.getDrawable()).getBitmap();
    				
    				String ruta = guardarImagen(getApplicationContext(), imagen, imagen); 
    				
    				Toast.makeText(getApplicationContext(), ruta, Toast.LENGTH_LONG).show();
    			}
    			
    		});
    		

    En el método onClick() tenemos 3 líneas, las cuales van a realizar lo deseado. Primero creamos un objeto de la clase Bitmap, en el cual mediante un cast a la clase BitmapDrawable podremos coger la imagen que hemos establecido en el ImageView. Este paso podríamos habernoslo ahorrado si hubieramos hecho todo el proceso en la AsyncTask, pero con esto podemos saber una de las maneras que hay de poder conseguir la imagen que tenemos establecida en los ImageView.

    Lo siguiente es la creación de un objeto del tipo String, donde le asignaremos el valor de retorno que nos retorne el método guardarImagen(), al cual le pasamos 3 parámetros:

    • Context: la información de la aplicación.
    • “imagen”: Esto no es mas que el nombre que le aplicaremos al archivo de la imagen que creemos, en este caso la he llamado “imagen”, pero perfectamente podríamos haber capturado algún nombre mediante un Dialog o un TextView.
    • imagen: Es el objeto Bitmap que hemos creado y hemos recogido del ImageView.

    Ahora procedemos a analizar el método guardarImagen() y lo que realiza:

  • Método guardarImagen()

    El método guardarImagen() es el siguiente:

    		private String guardarImagen (Context context, String nombre, Bitmap imagen){
    			ContextWrapper cw = new ContextWrapper(context);
    			File dirImages = cw.getDir(Imagenes, Context.MODE_PRIVATE);
    			File myPath = new File(dirImages, nombre + .png);
    			
    			FileOutputStream fos = null;
    			try{
    				fos = new FileOutputStream(myPath);
    				imagen.compress(Bitmap.CompressFormat.JPEG, 10, fos);
    				fos.flush();
    			}catch (FileNotFoundException ex){
    				ex.printStackTrace();
    			}catch (IOException ex){
    				ex.printStackTrace();
    			}
    			return myPath.getAbsolutePath();
    		}
    		

    Como vemos recibimos 3 parámetros, Context, String que es el nombre de la imagen y Bitmap que es la imagen.

    En este método lo que hacemos en un principio es crear unn objeto de la clase ContextWrapper con el cual extraeremos el directorio privado de nuestra aplicación en nuestro terminal.

    A continuación, mediante objetos del tipo File creamos las rutas, en el primer caso, si observamos la línea:

    		File dirImages = cw.getDir(Imagenes, Context.MODE_PRIVATE);
    		

    Estamos consiguiendo la ruta de nuestra aplicación, creando consigo una carpeta llamada “Imagenes”, la cual hacemos privada, por lo que solo nuestra aplicación podría acceder a ella.

    En el siguiente caso estamos creando la ruta de nuestra imagen, en la cual usaremos la del objeto dirImages concatenada con el nombre de nuestra imagen y su extensión “.png”.

    A continuación creamos un objeto de la clase FileOutputStream, el cual se encargará de crear un flujo de salida que escribe bytes en un archivo, aunque lo inicializamos a null, ya que llamaremos al constructor dentro de un bloque try-catch para manejar las excepciones que pueda dar.

    En el bloque Try-catch, construimos el objeto FileOutputStream, pasandole como argumento el objeto File que creamos con anterioridad, en este caso myPath, ya que contienela ruta completa a nuestra imagen. Si la ruta ya existiera, podríamos reemplazarla o añadirla.

    A continuación mediante el método compress de la clase Bitmap, elegimos un formato de compresión, la calidad de la imagen mediante un int, y pasamos como último argumento el objeto que hemos creado de al clase FileOutputStream. Por último, limpiamos el buffer de salida.

    Por último retornamos la ruta de la imagen en el terminal, que luego visualizaremos.

  • AndroidManifest.xml

    No debemos olvidarnos de agregar el permiso de uso de Internet a la aplicación, porque si no lo hacemos tendremos un error, para ello abrimos el archivo AndroidManifest.xml ubicado en nuestro directorio raiz del proyecto y agregamos la siguiente linea de código:

    		<uses-permission android:name=android.permission.INTERNET/>;
    		
  • Consultar archivo guardado

    Para consultar si el archivo ha sido bajado debemos abrir la perspectiva DDMS de Eclipse, para ello, vamos a Window/Other Perspective/Other, buscaremos en la lista DDMS y aceptaremos.

    Una vez abramos esta perspectiva en la ventana de la izquierda pulsamos sobre el emulador en funcionamiento. A continuación, en la derecha, pulsamos sobre “File Explorer”, como veremos en las siguientes imágenes;

    DDMS File Explorer

    A continuación, nos vamos al directorio “data”:

    DDMS data data

    Buscamos el nombre del paquete de nuestro proyecto y lo abrimos, donde encontraremos la carpeta que hemos creado, con el nombre modificado, pero que aunque sea diferentes, en el código seguirá siendo “Imagenes” como definimos:

    DDMS Imagenes

Una vez ya elaborados estos pasos, podríamos ejecutar nuestra aplicación y probarla:

Aquí una screenshot con el resultado final:

ScreenShot final

Aquí un video de la aplicación en ejecución:



Sin más, espero que sea de ayuda a quien busque una manera de almacenar imágenes, ya sean descargadas de internet u otros métodos, en la memoria interna del teléfono, en la próxima entrada veremos como guardarlas en la tarjeta SD o memoria externa del teléfono.

Cualquier aporte o corrección son bienvenidos!.

Saludos!!!

  • Jorge

    No me sale :/ …. En mi casa, no necesito descargar una imagen porque ya tengo una imagen en un ImageView solo hago el evento onclick y la funcion guardar Imagen …. luego busco la imagen como indica y por un explorador y nada ! Porfas haber si me echas una mano! Gracias

    • Buenas!, para empezar, te dá algún tipo de error?

  • Alfonso

    Muy Buenas, he intentado adaptar el código para una aplicación que quiero hacer, pero no me funciona y es porque no entiendo demasiado. El caso, quiero que mi aplicación coja imágenes de la galería y las ponga como fondo en los botones de la misma aplicación. Lo que ocurre es que cuando las pongo como fondo al salir de la aplicación y entrar de nuevo ya no están (salen los fondos de los botones por defecto) y supongo que es por no tener las imágenes que cargo de la galería en memoria interna y me gustaría que la aplicación al cargarlas las almacenase para que se mantengan los cambios. Un saludo, gracias.

    • Buenas Alfonso!,

      Por lo que me has explicado, el problema no es que no tengas las imágenes en la memoria interna (ya que no tiene nada que ver, pueden estar también en la memoria externa para el propósito que quieres, aunque puede ser mas lento en temas de rendimiento) sino que no tienes una manera de almacenar la imagen para cada botón. Debes de tener algún sistema para almacenar la ruta de esas imágenes y comprobar cada vez que se inicie la aplicación si existe alguna imagen para ese botón, en el caso de que exista, la asignas, en el caso de que no exista le asignas una predeterminada.

      Podrías solucionarlo guardando las rutas en las Preferences de la aplicación, y comprobar cada vez que se inicia la aplicación.

      Espero que te sea de ayuda!

      Saludos!!

  • Alfonso

    Muchas gracias, voy a probar a ver que tal me sale

  • anabrc

    Intenté y sí me salió, me sirvió de mucho. Gracias.

  • Norman

    y para guardarlo en una string como se hace??? XD

  • Cindy Hernandez

    Hola Excelente tutorial de verdad habia estado buscando esto por mucho tiempo, ya realice todo tal cual mensionas y me funciona sin errores, el problema que tengo es este:

    Tengo mi telefono android con root y puedo acceder a los archivos de las aplicaciones desde el, pero cuando abro la imagen que guarde mediante el ejemplo no se ve nada y dependiendo el visor de imagenes algunos dicen foto no disponible, ojala puedas ayudarme para saber que es lo que pasa por que despues de almacenarla necesito leerla y mostrarla podrias ayudarme??? te agradesco de antemano tu tiempo en leerme, un saludo!!!

  • Cindy Hernandez

    Hola yo de nuevo XD, realice mas pruebas y ya logre volver a leer la imagen y mostrarla en otro imageView y la muestra sin problemas se visualiza bien, solo el problema es al abrirla con los visores de imagenes que tengo instalados, ojala puedas ayudarme para saber cual es la razon de esto por que necesito que la imagen guardada no pierda su integridad, gracias de antemano.

    • Buenas Cindy,

      Es curioso lo que me comentas, sobre todo el hecho de que algún visor de foto no pueda abrirlas bien, le pone la extensión de la imagen correctamente?

      Saludos!

  • vagabundo05

    Buen tutorial, tengo una duda espero me puedas ayudar, de casualidad se puede crear un archivo de audio usando el micrófono del emulador??? el ejemplo seria que al correr la aplicación en el emulador y digas “Hola” se pueda reproducir(ya lo hice) y ademas grabarlo en un archivo(3gp, wav, etc) de antemano gracias

  • jairo

    si guardo mi imagen cuando vuelva a abrir aparecera la imagen que guarde ???

    • Buenas Jairo,

      En teoría si, debería seguir guardada a no ser que el usuario borre los datos de la aplicación o la propia aplicación lo borre mediante algo que tengas programado.

      Si por casualidad la guardas como Caché, entonces el sistema podría borrarla sin previo aviso.

      Espero haber sido de ayuda.

      Saludos

  • Angel

    Amigo que tal, gracias por el codigo, no me da error pero no puedo ver mi imagen cuando entro al explorador de archivos del telefono, la ruta que me da el mensaje toast es : data/data/com.example.proyectox/app_Imagenes/imagen2.jpg
    otra pregunta, que pasa si descargo otra imagen ? se sobreescribe la anterior? gracias.

    • Buenas Angel,

      La razón por la que no te sale la imagen con el explorador de archivos es porque lo guarda en la ruta interna del teléfono. Esto quiere decir que tendrías que tener el teléfono con root para poder acceder a esas carpetas que son las internas de las aplicaciones. Si usas el ejemplo con un emulador de Android, podrás hacerlo con el Monitor, pero esto es porque los emuladores son como “root” y puedes verlo de esa manera.

      Para poder verlo con el explorador de archivos, quizás deberías guardarlo en la memoria externa.

      Si en el caso de que sobreescribieras la imagen (mismo nombre en este caso) pisaría la anterior. Para evitar esto puedes cambiarle el nombre y ya no habría problema.

      Espero que te sea de ayuda Angel.

      Saludos!

  • Que tal amigo, gracias por tu aporte, adapte una parte del codigo a mi proyecto. Saludos