69 comentarios el “Base de Datos SQLite en Android

  1. Hola David,

    Me falla la aplicación al volver de la Activity NuevaNota. Da un error de «Failure delivering result» indicando «Attempt to re-open an allready-closed object» para la base de datos ¿Que puede ser?

    Gracias por tu explicación

  2. Buenas Adolfo,

    Efectivamente falla, perdóname, parece que agregué los métodos onPause y onResume después de grabar el vídeo y no me dí cuenta.

    El error es básicamente que al pasar a la actividad de NuevaNota se cierra la conexión con la base de datos, y al volver a la actividad principal, se ejecuta directamente el método onActivityResult por lo cuál la conexión con la base de datos está cerrada, y este método hace uso de la base de datos, luego el problema reside ahí:

    Para solucionarlo basta con añadir la línea:

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    	// TODO Auto-generated method stub
    	Log.d("Result", "Se ejecuta onActivityResult");
    	super.onActivityResult(requestCode, resultCode, data);
    	if (requestCode == this.requestCode && resultCode == RESULT_OK) {
    		// Actualizar el Adapter
    		dataSource.open();
    		refrescarLista();
    	}
    }
    

    Abrir de nuevo la conexión antes de interactuar de nuevo con la base de datos.

    Muchas gracias por avisarme del error, voy a subir de nuevo el proyecto para que esté disponible correctamente, y corregiré en el código algunas pinceladas.

    Saludos, y gracias!!

    • Hola David,

      Ha quedado perfecto. El ejemplo me ha ayudado mucho y está muy bien explicado.

      Muchas gracias

  3. Una pregunta y si quisieramos gaurdar la base en una ruta determinada, se que cuando creas la base se gaurda en la carpeta data/data/ nombre del paquete el problema es que cuando paso mi aplicacion a mi telefono a esa direccion solo puedes accesar como root y no quiero rootear mi telefono solo por ese detalle, entonces mi pregunta es ¿Existe alguna forma de indicarle la ruta donde quiero que guarde la base?

  4. Buenas Jose Luis,

    Según tengo entendido en el método openDataBase() puedes especificar una ruta donde tengas guardada la Base de Datos. Esto quiere decir que al igual que puedes abrirla puedes crearla y transportarla a otro lugar.

    Al fin y al cabo es un archivo que puedes mover a la SD o cualquier otro directorio.

    Entre los métodos de la clase SQLiteDatabase puedes encontrar alguno que te pueda servir a la hora de crearla en otro lugar, por ejemplo en el constructor de la subclase que extiende de SQLiteOpenhelper podemos leer lo siguiente:

    Create a helper object to create, open, and/or manage a database. This method always returns very quickly. The database is not actually created or opened until one of getWritableDatabase() or getReadableDatabase() is called.

    Por lo que viendo esto hay que localizar donde pasa esto y trabajar en crearla en otra ruta a tu deseo.

    Otra cosa que podrías hacer es crear la base de datos normalmente, y mediante alguna acción (un Button, al cerrar la aplicación, diariamente, etc) exportarla en otro lugar (una simple copia) para poder tratar con ella. De esta manera seguirás teniendo tu base de datos en la memoria interna, y cuando quieras, una copia en otro lugar, ya sea por tema de backups o porque quieres sacar los datos para sacar alguna estadística, la finalidad es lo de menos.

    También todo este depende mucho de como quieras enfocar la aplicación, pero lo que he leído por ahi, es que lo menos recomendable es almacenar bases de datos en la memoria externa o SD, ya que su rendimiento es bastante inferior, aunque esto es solo un dato auxiliar.

    Espero haber sido de ayuda, al menos en guiarte un poco en tu problema.

    Saludos!

    • aaaaaaaaaaa ok asi queda mas claro y se por donde emepzar a bsucar, gracias por responder y vere si logro cambiarla de lugar, esto es mas que nada para que aplicaciones como sql viewer puedan accesar a el

      • Igualmente si lo que quieres es ver como va la base de datos en tiempo de desarrollo, puedes exportarla con el Eclipse para mirarla, comprobar, etc.

        Saludos!

  5. Hola 🙂
    Antes que nada muchas gracias por el post, me ha servido mucho¡¡
    Una pregunta, hay alguna forma de ver la base de datos en el celular, para checar si se estan insertando correctamente los registros??
    De antemano muchas gracias 😀
    Saludos¡¡¡

  6. Buenas liz,

    Efectivamente se puede, pero no directamente del terminal por así decirlo.

    El Android SDK dispone de una «perspectiva» llamada DDMS en la cual podemos buscar dentro de nuestro emulador, bien para agregar archivos o para extraerlos.

    Para abrir esta perspectiva, debes dirigirte a Window -> Other Perspective -> DDMS, y si no te aparece en la lista, puedes darle a Other y buscar entre el listado.

    Una vez abierto se te abrirá una pestaña en la parte superior derecha del IDE, en la cual aparece el emulador o dispositivo que está ejecutando nuestra aplicación a la izquierda. Al seleccionarlo buscaremos el nombre del paquete de la aplicación que estamos ejecutando y en la parte derecha podemos entrar dentro de el y ver sus archivos. Una vez ahí, nos dirigimos al directorio data/data/, buscamos el paquete de nuestra aplicación, y a continuación en la carpeta databases tenemos la base de datos en un archivo, que podemos extraer para abrirla con algún programa que maneje bases de datos sqlite.

    En el siguiente vídeo lo tienes de forma mas visual:

    Espero que te sea de ayuda,

    Saludos!!

  7. Hola, antes de nada muchas gracias por el tutorial, pero queria hacerte una pregunta.
    Es posible acceder a una base de datos que no ssea la creada desde nuestra app? En caso afirmativo como se haría??

    Estoy intentando conectarme a traves de:

    Class.forName(«SQLite.JDBCDriver»);
    Connection conn = DriverManager.getConnection(«jdbc:sqlite:» + Ruta );

    pero no lo consigo, y si tan sólo intento hacer el open con:

    myDataBase = SQLiteDatabase.openDatabase(Ruta, null, SQLiteDatabase.OPEN_READWRITE);

    tambien me lanza una excepción.

    ¿podrías echarme una mano?

    gracias

  8. Buenas Marta,

    Hace no mucho respondí una duda parecida a la tuya. Según leí en la información oficial sobre la clase SQLiteOpenHelper, la subclase que hereda de esta puede abrir un fichero de una base de datos SQLite en una ruta donde tengas la base de datos, te pego aquí lo que decía en la documentación:

    Create a helper object to create, open, and/or manage a database. This method always returns very quickly. The database is not actually created or opened until one of getWritableDatabase() or getReadableDatabase() is called.

    Como podemos sacar en claro, en el constructor de la clase que herede de SQLiteOpenHelper es donde ponemos la ruta, y al usar el método getReadableDatabase() o getWritableDatabase() es cuando ya podemos trabajar con ella.

    Si lo que quieres sin embargo es comunicarte con algún sistema de base de datos externa en la nube, ya sea MySQL por ejemplo, lo idóneo sería con unos Web Services que te dejen consultar y recibir los datos que se quieran :).

    Espero te sea de ayuda, aunque es mas que nada una pequeña guía de por donde hay que ir, si sigue sin salirte o algo comentamelo y vemos que pasa 🙂

    Saludos!!!

    • Hola David, gracias por tu respuesta, pero no consigo abrir la base de datos.

      Me he creado una clase que extiende de SQLiteOpenHelper que he llamado BaseDatosNew, y en ella tan sólo ejecuto el constructor ( super(contex, RutaB, null, 1); context y RutaB pasado por parametro)y el onCreate y onUpgrade vacios.

      Por otro lado me he creado otra clase que también extiende de SQLiteOpenHelper donde tengo el constructor (super(context, RutaB, null, 1); todo pasado por parametro) y los métodos onCreate y onUpgrade vacios y el close y Open. En el Open tengo:

      BaseDatosNew dbHelper = new BaseDatosNew(context, RutaB);
      SQLiteDatabase database = dbHelper.getWritableDatabase();
      return this;

      y me dá error en el open.

      sqlite3_open_v2(«/data/data/com.mio.mibibliotecaparticular/databases/mibiblioteca.sqlite», &handle, 6, NULL) failed
      android.database.sqlite.SQLiteCantOpenDatabaseException: unable to open database file
      at android.database.sqlite.SQLiteDatabase.dbopen(Native Method)
      at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:1013)
      at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:986)
      at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:1051)

      No sé si podrías echarme una mano, por que por más vueltas que le doy no encuentro el fallo. de hecho, si cambio BaseDatosNew por otra clase que es BaseDatos que es la de mi propia base de datos en la app, no hay fallo.

      ¿Es posible que sea por la versión? , En principio no sé que version tiene la base de datos NEW, le he puesto 1 por poner algo, porque como no tengo nada en los métodos, ni siquiera tengo puesto el onDowngrade imagino que no hará nada, pero no lo sé.

      Te agradeceria mucho si pudieras echarle un vistazo a esto y darme alguna ayuda

      gracias

  9. Hola, en primer lugar gracias por este blog, estoy estudiando desarrollo de aplicaciones multiplataforma y me ha sido de mucha ayuda para la aplicación que estoy desarrollando.
    Mi problema es el siguiente.
    El error que me da es java.lang.IllegalStateException: attempt to re-open an already-closed object, leí una solución a él en los primeros comentarios pero mi código es algo diferente, me explico:
    Tengo una base de datos mysql de la que recojo los datos, pero para poder ver los datos aún sin conexion a internet, en lugar de mostrar los datos de mysql, los inserto en una base de datos SQLite, y son los datos de esta, los que muestro. Mi activity principal, se encarga de recoger todo lo que necesito de mysql y volcarlo en sqlite, hasta aquí todo bien. Cuando esta tarea finaliza, creo un intent e inicio una nueva activity, en la cual muestro datos. Es, al iniciar esta segunda pantalla, donde se produce el error.
    En la principal abro el datasource en el oncreate y lo cierro antes de iniciar la nueva activity.
    En la siguiente activity, abro el mismo datasource tambien en el oncreate.
    En ambas cierro en onPause y abro en onResume.

    Espero que me haya explicado bien y que puedas ayudarme, un saludo

    • Buenas Enmanuel,

      Este error relacionado con la base de datos puede darse en varias ocasiones. Puede darse bien por el objeto de la clase que accede a la base de datos, o bien puede darse porque puedes tener algún método que usa un objeto de la clase Cursor que no se cierra al terminar el método.

      No es que puedan darse los errores solo en estos casos, sino que son los mas frecuentes al trabajar con bases de datos.

      También leí algunos comentarios en StackOverflow de algunas personas que decían que no era del todo necesario cerrar la base de datos en todos los casos, pero no puedo decirte si esto es lo correcto o no ya que intervienen bastantes factores :).

      Espero que te sirva de ayuda !

      Saludos!!

      • Gracias por tu rápida respuesta.
        Efectivamente era eso, no cerraba el cursor al terminar un método. 🙂
        De nuevo, muchas gracias.

      • Parece que hablé antes de tiempo.
        Sigue dándome el error. El objeto que no puede abrir, parece ser que es la base de datos «SQLiteDatabase».

        Te adjunto el error, por si viendolo puedes divisar cual es mi problema.
        FATAL EXCEPTION: main
        java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /data/data/com.example.gtafacturacion/databases/artabria
        at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:55)
        at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1437)
        at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1339)
        at sqlite.FacturasDataSource.crearFactura(FacturasDataSource.java:96)
        at activities.ActualizarDatos.insertarFacturas(ActualizarDatos.java:132)
        at activities.ActualizarDatos.access$4(ActualizarDatos.java:128)
        at activities.ActualizarDatos$ClassHandlerConsultarDatos.handleMessage(ActualizarDatos.java:283)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:137)
        0at android.app.ActivityThread.main(ActivityThread.java:5041)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:511)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
        at dalvik.system.NativeStart.main(Native Method)

      • De verdad siento mucho comentar tanto, pero ya he encontrado la causa.
        La consulta a la base de datos externa la realizaba en el doinbackground de una clase asynctask, y en el onpostexecute, cerraba el datasource.
        Bien, en el doinbackground llamo a mun metodo consultarX, que asu vez inicia un thread que se encarga de conectar con la base de datos y traer los resultados. Parece ser que antes que que obtiviese los resultados ya se ejecutaba el onPostExecute, y por lo tanto se cerraba la bd.

        Un Saludo.

      • No te preocupes por comentar 🙂

        Si te es mas fácil puedes abrir la base de datos en cada onCreate y cerrarlas únicamente al salir de la Activity, ya sea al ir a otra activity diferente o al volver, no creo que afecte mucho al rendimiento, aunque todo hay que estudiarlo antes claro, las ventajas como las desventajas.

        Saludos y me alegro de que lo hayas sacado!

  10. Hola, soy nuevo programando android y no entiendo la necesidad de ese método onUpgrade que borra y la tabla y la vuelve a crear… qué significa eso? Por qué hacerlo? En qué casos se llama a ese método? Es necesario borrar y crear la tabla siempre que se hace algo nuevo como insertar o borrar? No tiene sentido no? Gracias de antemano

    • Buenas «Desastroso»,

      Te explico como funciona así por encima esta clase que hereda de SQLiteOpenHelper:

      1. El método onCreate se ejecuta cuando no existe una base de datos y debe crearse. En este método es donde se crean las tablas y se introducen algunos datos, en caso de que sea necesario o la aplicación lo requiera.
      2. El método onUpgrade es necesario, ya que en el caso de que en un futuro veas conveniente actualizar tu base de datos, agregando una tabla mas, etc, es decir, solo se ejecuta si cambia algo relacionado con el «Esquema» de la base de datos.

      Por tanto, no te preocupes por insertar, actualizar o borrar datos, ya que no se borrará ni la base de datos ni se creará de nuevo. Esta clase «representa» tu base de datos, pero estos métodos son obligatorios implementarlos ya que son totalmente necesarios.

      No sé si me he explicado muy bien, pero creo que algo puede serte de ayuda.

      Saludos!!!

      • Perfectamente; leer manuales puede resultar, a veces, tan frustrante como gratificante es tu explicación. Mil gracias.

  11. Buenas, una pregunta, como podria hacer para que mostrara el nombre de cualquier item que seleccione en una nueva ListView ubicada en otra activity?.

    un saludo, y gracias por tu gran explicacion!. 🙂

  12. Excelente tutorial, lo he estado probando y me surgio una pequeña duda, si tengo 4 tablas tengo que agregar todos los metodos de las diferentes tablas a la clase «NotasDataSource» o sería conveniente hacer una clase por cada tabla. Gracias.

  13. Tengo una duda en la clase Nota aparece el siguiente método:

    @Override
    public String toString(){
    return texto;
    }

    por favor ¿Podrías decirme para que sirve / Cuál es su función?

    • Buenas Donnie,

      El método toString() es un método que TODAS las clases en Java tienen, y es decisión de cada persona hacer «Override» o sustituirla para adaptarla a su clase.

      Normalmente se usa para devolver el estado de un objeto, o toda la información de este, mediante una representación en String.

      En este ejemplo, lo uso porque el ArrayAdapter recibe un List, y para no tener que crear un ArrayAdapter personalizado, el adapter usa el método toString() para poner en cada row del ListView en este caso el texto de nuestra Nota.

      Pos otro lado, supongamos que queremos imprimir todo el estado de un objeto nota, podríamos hacerlo de esta manera:

      @Override
      public String toString(){
        return "El id es " + id + " y el texto es " + texto;
      }
      

      Es un ejemplo bastante vulgar, pero te puede servir para saber su función, y en este tutorial, para qué se usa exactamente.

      Espero que te sea de ayuda,

      Saludos!!!

      • Hola saludos

        Tengo una duda en que momento se hace uso del toString() estuve siguiendo el curso y al momento de llenar el ListView me da la siguiente exception java.lang.NullPointerException

      • Buenas Paul,

        El método toString(), aunque no se vea su uso en el código, lo usa el ArrayAdapter internamente para rellenar las filas del ListView. por ejemplo, si hiciéramos lo siguiente en nuestro método:

        public String toString(){
           return "Hola";
        }
        

        En todas nuestras filas del ListView tendríamos un «Hola» como texto.

        Espero que sea de ayuda 😉

        Saludos!

  14. Cómo debería modificar ese código si quisiera ingresar información desde 2 textFields en un solo item. En mi caso, el nombre de un cliente y su respectivo pedido. He intentado modificando el codigo, pero no me ha salido bien, espero puedas ayudarme en eso.
    Te adjunto la modificación que hice:
    http://sdrv.ms/12d07fK

    • Buenas noches Javier,

      He visto tu ejemplo y estas a nada de lograrlo, en el método onClick donde extraer el valor de los diferentes EditText podrías hacerlo así:

      Primero, puedes crear otro constructor para la clase Pedido, y así hacer que tu método de crear un registro acepte un objeto de la clase Pedido

      public Pedido (String nombre, String pedido){
      		this.nombre = nombre;
      		this.pedido = pedido;
      	}
      

      De esta forma, puedes crear otro método en el datasource para que acepte un objeto de la clase Pedido:

      public void crearPedido(Pedido nuevo){
      		ContentValues values = new ContentValues();
      		values.put(TablaPedidos.COLUMNA_NOMBRE, nuevo.getNombre());
      		values.put(TablaPedidos.COLUMNA_PEDIDO, nuevo.getPedido());
      		db.insert(TablaPedidos.TABLA_PEDIDOS, null, values);
      	}
      

      También puedes adaptar el mismo método para que acepte 2 String

      public void crearPedido(String nombre, String pedido){
      		ContentValues values = new ContentValues();
      		values.put(TablaPedidos.COLUMNA_NOMBRE, nombre);
      		values.put(TablaPedidos.COLUMNA_PEDIDO, pedido);
      		db.insert(TablaPedidos.TABLA_PEDIDOS, null, values);
      	}
      

      Igualmente puedes tener ambos creados, ya que si el método tiene el mismo nombre, pero distintos parámetros se entiende que el método está siendo «sobrecargado», lo cual java soporta y es común en su uso, de tal manera que quedaría así:

      public void crearPedido(String nombre, String pedido){
      		ContentValues values = new ContentValues();
      		values.put(TablaPedidos.COLUMNA_NOMBRE, nombre);
      		values.put(TablaPedidos.COLUMNA_PEDIDO, pedido);
      		db.insert(TablaPedidos.TABLA_PEDIDOS, null, values);
      	}
      	
      	public void crearPedido(Pedido nuevo){
      		ContentValues values = new ContentValues();
      		values.put(TablaPedidos.COLUMNA_NOMBRE, nuevo.getNombre());
      		values.put(TablaPedidos.COLUMNA_PEDIDO, nuevo.getPedido());
      		db.insert(TablaPedidos.TABLA_PEDIDOS, null, values);
      	}
      

      Espero que te haya sido de ayuda, cualquier duda no dudes en comentarlo.

      Saludos!!

      • Mil gracias por responder tan rapido. Probe con lo que dices y solo me queda este problema:

        private Pedido cursorToPedido(Cursor cursor) {
        Pedido pedido = new Pedido(nombre, pedido);
        pedido.setId(cursor.getLong(0));
        pedido.setNombre(cursor.getString(1));
        pedido.setPedido(cursor.getString(2));
        return pedido;
        }

        En el cursor, por alguna razón, no reconoce el parametro «nombre» de esta linea:
        Pedido pedido = new Pedido(nombre, pedido);
        Mas bien, si no fuera mucha molestia, podrias prestarme el codigo de esto ya resuelto?

        Acá dejo el código actualizado: http://sdrv.ms/12d07fK

      • Buenas javier,

        El problema que tienes en el método es que estás creando un pedido, y pasandole 2 argumentos que no existen, nombre y pedido, que no existen de manera local en el método.

        Lo único que deberías hacer en este caso es cambiar el orden de lo que haces en este método, quedando tal que así:

        private Pedido cursorToPedido(Cursor cursor) {
            long id = cursor.getLong(0);
            String nombre = cursor.getString(1);
            String pedido = cursor.getString(2);
            
            // Para pasar tambien el id, deberías crear otro constructor pero que acepte 3 parámetros
            Pedido pedido = new Pedido(id, nombre, pedido);
            
            return pedido;
        }
        

        o bien

        private Pedido cursorToPedido(Cursor cursor) {
            // Para pasar tambien el id, deberías crear otro constructor pero que acepte 3 parámetros
            Pedido pedido = new Pedido(cursor.getLong(0), cursor.getString(1), cursor.getString(2));
            return pedido;
        }
        

        El nuevo constructor es fácil y quedaría así:

        public Pedido (long id, String nombre, String pedido){
            this.id = id;
            this.nombre = nombre;
            this.pedido = pedido;
        }
        

        Espero que te sea de ayuda;)

        Saludos!

      • Así y todo aún no me termina de salir el ejercicio, siempre se detiene a la hora de ejecutar y ahora ya no sé que error puede tener porque ya ni avisa el eclipse… mil gracias por toda tu ayuda, al menos pude llegar a avanzar mucho este ejercicio.

      • Buenas noches Javier,

        Si el programa no se llega a ejecutar, revisa todo aquello que se ejecute en el método onCreate de la Activity principal, y consulta el Logcat para ver que excepción te lanza y la línea en la que te aparece 😉

        Espero que te sea de ayuda,

        Saludos!

  15. Hola, gracias por el tutorial!

    Se me ocurre una pregunta, seria posible que al pulsar sobre cada registro, se ejecutara una acción diferente? Es decir, por ejemplo:
    -Al apretar sobre Nota 1, accedes a una nueva ventana donde tiene un Texto 1, la fecha en la que ha sido creada…
    -Al apretar sobre Nota 2, accedes a una nueva ventana donde tiene un Texto 2, la fecha en la que ha sido creada…

    Y otra cuestión, existe la posibilidad de crear tablas nuevas en una base de datos con los mismos nombres de columna? Y como se accederia a dichas tablas? Por ejemplo,

    – Ejecuto un código que me dice el tiempo hoy lunes. Luego al apretar sobre nota 1 apareceria: la fecha y el tiempo del lunes (soleado, por ejemplo)
    – Ejecuto un código que me dice el tiempo hoy martes.Luego al apretar sobre nota 2 apareceria: la fecha y el tiempo del martes (nublado, por ejemplo).

    Pero si yo volviera a apretar nota 1, volveria a salir el tiempo del lunes. Es decir, que no se me sobreescribieran los datos, sino que se grabaran en tablas diferentes

    Quizá es un poco larga la pregunta. Antes que nada, muchas gracias!

    • Buenas Frank,

      Para lo primero, lo único que tendrías que hacer es crear una Activity que se encargue de mostrar la información que quieras. O bien puedes extraer la nota en la primera Activity y mandarla a la segunda donde muestras la información, o bien puedes obtener el id y en la segunda extraer la nota de la base de datos y mostrarlo.

      Para lo segundo, simplemente debes agregar el código de crear una tabla nueva con los nombres de columna que quieras, lo único que tiene que ser diferente para que no haya conflicto son el nombre de las tablas. Para acceder a estas tablas, simplemente tienes que cambiar las consultas SQL en el datasource, o bien crear uno nuevo para esa tabla y agregar los métodos que necesites en el.

      Espero que te sirva de ayuda,

      Gracias!!

  16. hola
    Primero que todo gracias
    segundo, mi programa no corre, lo único diferente es que el compilador de eclipse me mando a quitar los @override de algunas funciones, por que de lo contrario no dejaba crear el apk. ahora crea el apk lo instala en el tablet y en el virtual device pero al dar click en el boton de crear nueva nota no hace nada.

    Puede que sea por ser rookie en esto, no logro hayar el error, gracias de antemano por tu ayuda
    Saludos
    Sir.

    • Buenas Sirmchercar,

      Sin duda es raro que Eclipse te diga de quitar algunos @Override, ya que algunos son vitales para sustituir la funcionalidad de un método en concreto. También me parece raro, ya que cuando por ejemplo aplicamos el lvNotas.setOnItemClickListener(this);, al implementar el método, la etiqueta de @Override la incluye automáticamente, por lo que es raro que nos mande quitarla luego.

      Revisa bien el Logcat para ver si dice algo con los @Override, porque es muy curioso y raro a la vez.

      Espero haber sido de ayuda, aunque en realidad no te he podido ayudar mucho, porque parece que todo está relacionado con lo de tener que quitar los @Override, por lo que muchas funcionalidades no se activan, o por ahí deben ir los tiros.

      Saludos!

  17. Hola, muy claro todo los pasos.
    Yo lo que estoy buscando por toda la web, es informacion de como hacer para que se tomen los datos desde SQLite (ej, nota 1, nota 2..etc) y se puedan enviar por mail o mensaje de texto. Se que es muy complejo…pero en realidad lo dificil no es crear la opcion de que el usuario pueda enviar el mail o el mensaje de texto….sino crear la actividad para que la aplicacion tome los datos desde la base de datos utilizada.

    por ej.: en este caso……si yo quisiera mandarle un mensaje a un amigo que diga «nota 1, nota 2, nota 3» se entiende?

    Espero se haya entendido mi consulta

    Saludos

    • Buenas ditox26,

      Eso no es nada complicado, si sabes un poco de lenguaje SQL serás capaz de sacar los datos de las tablas sin ningún problema, que parece ser que es lo que necesitas, extraer datos de las tablas. Te lo explicaría sin problema, pero el tema de SQL es un tema bastante largo, ya que pueden ser consultas muy simples o muy complejas.

      En el tutorial se vé que hago una consulta, con al cual creo las nota sy extraigo los valores de la tabla, quizás te sirva de algo 😉

      Saludos!!

  18. Hola me gustara saber si pueden ayudarme con el siguiente problema:

    Yo tengo guardado los datos en el celular. Entonces lo que quiero es que en otro celular que tenga el mismo programa se guarden los mismos datos.
    Como hago para sincronizarlos y de paso si se puede hacer una app de escritorio para mandar datos al celular.

    De antemano muchas gracias. espero puedan ayudarme

    • Buenas geovanyxxx,

      La idea mas común para este tipo de cosas sería mediante un WebService en un servidor, que sirva como puente entre ambos teléfonos identificados de algún modo. Siempre existen otras alternativas, como pueden ser el uso de bluetooth o el NFC, pero estos nunca los he usado por lo que no puedo guiarte demasiado con ello.

      Claro que es posible crear una aplicación de escritorio para mandar datos, aunque quizás en la época en la que estamos, en el que el mundo web está en alza, te salga mejor hacer una especie de web, con login y password y desde ahí poder mandar datos a los teléfonos, bien mediante la plataforma GCM (Google Cloud Messaggins) o simplemente crear datos y que la aplicación cuando lo necesite los extraiga del servidor.

      Espero haber sido de ayuda,

      Saludos!!!

  19. Hola david antes que nada muy buen proyecto y solo tengo una duda, como le puedo hacer para solo agregar cuantas listas quiera sin que me este abriendo a cada rato la activity donde se muestra la lista de las notas agragadas? de antemano muchas gracias

  20. es posible localizar el archivo de base de datos una vez instalado en el dispositivo ???? espero me puedas ayudar de ante mano buenos tutoriales gracias

    • Buenas Hugo,

      Puedes usar este método para localizar la ruta a la base de datos:

      context.getDatabasePath("Nombre de la Base de Datos");
      

      Con esto recibirás un objeto de la clase File con el que puedes obtener información sobre el archivo.

      Espero que te sea de ayuda!

      Saludos!!!

      • gracias ya asi para completar esa base la puede pasar a una sd para manipularla mediante un manejador sera q podras darme algun tip

      • Buenas hugo,

        En los primeros comentarios me comentaron algo parecido.

        Si a lo que te refiere es a poder sacar la base de datos de la aplicación, si estás haciéndolo por medio de un emulador, puedes extraer la base de datos por medio de Eclipse.

        Aquí tienes el video que grabé para mostrarselo a otro visitante con anterioridad: http://www.youtube.com/watch?v=r7PhQTZRYes

        Espero que te sea de ayuda.

        Saludos!

  21. Hola,

    Ante todo muchas gracias por tu tutorial, realmente me has solucionado el tema de acceder a las BBDD en android que ya me tenía loco…

    Todo me funciona correctamente, salvo que en la lista no me aparece el valor que yo quisiera.
    En tu ejemplo tienes una lista de la clase Notas. Bien, como haces para que el valor que te aparece en la lista sea el valor del campo private String texto;?

    En mi caso tengo otra clase definida, pero solo cambia que tengo más variables.

    Lo que me aparece a mi en la lista es la concatenación del package+nombre de mi clase seguido de un número.

    Como lo haría si yo quisiera que el valor a mostrar en la lista dentro de mi clase sea el de una variable en concreto?

    Muchas gracias por adelantado,

    Un saludo!

    • Vale ya lo he descubierto, no había puesto la función toString en mi clase:

      public String toString() {
      return wms_name;
      }

      Con esto ya tengo el nombre que es lo que quería mostrar.

      Saludos!

      • Perdona Sergio, he estado ocupado y no he podido echarle un vistazo al blog desde hace tiempo.

        Efectivamente, la clase ArrayAdapter hace uso del método toString que tenga la clase para mostrarlo en cada celda. Es por ello que si no existe este método, no mostrará nada o mostrará algo que no debe.

        Otra forma de hacer lo que quieres de manera que muestre mas datos, es haciendo una clase que herede o bien de ArrayAdapter o de BaseAdapter, y con ello personalizar cada celda a tu gusto.

        Tenía un tutorial sobre ello pensado desde hace tiempo pero no he logrado sacar demasiado tiempo, pero espero hacerlo pronto, ya que es útil y creo que es lo que mas se usa en la programación para dispositivos móviles.

        Un saludo, y lo dicho, perdona por no haberte respondido.

  22. Hola, soy muy nueva en este tema pero muy buena explicación!! Quisiera saber (si puedes ayudarme) como hago para consultar los datos de una base de datos Sqlite ya antes creada??

    Saludos, y gracias nuevamente!!

    • Buenas Daniela.

      Si lo que quieres es que la aplicación ya tenga una base de datos que va incluida en el propio APK, para esto deberías meterle en la carpeta /assets de tu proyecto.

      El problema, es que no podrás consultarla desde la aplicación así porque sí, sino que en el proceso de creación, harías una copia de ella en local, la cual si podrías consultar y manipular. (Este link de stackOverflow resume el proceso: http://stackoverflow.com/questions/9109438/how-to-use-an-existing-database-with-an-android-application )

      El problema de este método, y ya lo habrás visto, es que en assets tendrás una copia que ocupará espacio en tu aplicación y no podrás borrar ya que va dentro de la compilación.

      Otro método es sincronizar una base de datos local con algún tipo de API Web para llenarla de datos, pero esto es todo según como se tenga pensado y el objetivo y estructura de los datos.

      Saludos!!

  23. Hola, gracias por este tutorial.

    Una duda:

    en la clase NotasDataSource, en el método open() porqué no se llama a MySQLiteOpenHelper.onCreate() antes que al writeable? Porque en el constructor de NotasDataSource al llamar al constructor de MySQLiteOpenHelper ya se llama automáticamente al método onCreate de esta clase?

    No sé si me he explicado bien.
    Gracias. Un saludo!

    • Buenas Roberto,

      El método onCreate de MySQLiteOpenHelper es llamado automáticamente por el Framework cuando se intenta acceder a la base de datos, por lo cual la llamada a esté método es completamente automático.

      Saludos!!

  24. disculpa una pregunta

    ¿por que cuando ya la estoy emulando le pongo agregar nueva nota me dice que ocurrio un problema y no me saca de la app ? y ¿como puedo hacerle para ponerle como recordatorios que le ponga fecha y hora y que me notifique ?

    • Buenas Gabriel,

      Siento decirte que no puedo saber porque se te cierra si no me das algo mas de datos, o al menos la excepción que te lanza.

      Sé que al principio mi código tenía un error, pero me lo notificó un usuario y lo arreglé.

      Si me dices que error te dá podría ayudarte mas fácilmente.

      Por otro lado para hacer lo de los recordatorios puedes usar la api de AlarmManager que ofrece a Android ara establecer alarmas.

      Espero haber sido de ayuda.

      Saludos!

      • je si ya descarge tu codigo y si funciona 😀 oye pero no me puedes mostrar el codigo de AlarmManager de como se integraria en este mismo codigo de esta app que hiciste ? porfavor es que apenas voy empezando con esto de android 😀

      • Buenas Gabriel,

        Si en realidad estás aprendiendo en Android, quizás fuera mejor idea estudiarte la API y empezar a jugar con ella, si yo te facilito el código, no aprenderás a usarlo y adaptarlo a tus necesidades.

        Saludos!

  25. je si ya descarge tu codigo y si funciona 😀 oye pero no me puedes mostrar el codigo de AlarmManager de como se integraria en este mismo codigo de esta app que hiciste ? porfavor es que apenas voy empezando con esto de android 😀

  26. je si ya descarge tu codigo y si funciona 😀 oye pero no me puedes mostrar el codigo de AlarmManager de como se integraria en este mismo codigo de esta app que hiciste ? porfavor es que apenas voy empezando con esto de android 😀

  27. Hola, a he copiado todo igual y me da un error en el método startIntentForResult de la clase NotasActivity.

    Te copio y pego el LogCat:

    04-14 20:21:00.540: E/AndroidRuntime(16833): FATAL EXCEPTION: main
    04-14 20:21:00.540: E/AndroidRuntime(16833): java.lang.IllegalStateException: Could not execute method of the activity
    04-14 20:21:00.540: E/AndroidRuntime(16833): at android.view.View$1.onClick(View.java:2185)
    04-14 20:21:00.540: E/AndroidRuntime(16833): at android.view.View.performClick(View.java:2585)
    04-14 20:21:00.540: E/AndroidRuntime(16833): at android.view.View$PerformClick.run(View.java:9299)
    04-14 20:21:00.540: E/AndroidRuntime(16833): at android.os.Handler.handleCallback(Handler.java:587)
    04-14 20:21:00.540: E/AndroidRuntime(16833): at android.os.Handler.dispatchMessage(Handler.java:92)
    04-14 20:21:00.540: E/AndroidRuntime(16833): at android.os.Looper.loop(Looper.java:130)
    04-14 20:21:00.540: E/AndroidRuntime(16833): at android.app.ActivityThread.main(ActivityThread.java:3691)
    04-14 20:21:00.540: E/AndroidRuntime(16833): at java.lang.reflect.Method.invokeNative(Native Method)
    04-14 20:21:00.540: E/AndroidRuntime(16833): at java.lang.reflect.Method.invoke(Method.java:507)
    04-14 20:21:00.540: E/AndroidRuntime(16833): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912)
    04-14 20:21:00.540: E/AndroidRuntime(16833): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:670)
    04-14 20:21:00.540: E/AndroidRuntime(16833): at dalvik.system.NativeStart.main(Native Method)
    04-14 20:21:00.540: E/AndroidRuntime(16833): Caused by: java.lang.reflect.InvocationTargetException
    04-14 20:21:00.540: E/AndroidRuntime(16833): at java.lang.reflect.Method.invokeNative(Native Method)
    04-14 20:21:00.540: E/AndroidRuntime(16833): at java.lang.reflect.Method.invoke(Method.java:507)
    04-14 20:21:00.540: E/AndroidRuntime(16833): at android.view.View$1.onClick(View.java:2180)
    04-14 20:21:00.540: E/AndroidRuntime(16833): … 11 more
    04-14 20:21:00.540: E/AndroidRuntime(16833): Caused by: android.content.ActivityNotFoundException: Unable to find explicit activity class {org.example.notas/activities.NuevaNotaActivity}; have you declared this activity in your AndroidManifest.xml?
    04-14 20:21:00.540: E/AndroidRuntime(16833): at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1408)
    04-14 20:21:00.540: E/AndroidRuntime(16833): at android.app.Instrumentation.execStartActivity(Instrumentation.java:1382)
    04-14 20:21:00.540: E/AndroidRuntime(16833): at android.app.Activity.startActivityForResult(Activity.java:2833)
    04-14 20:21:00.540: E/AndroidRuntime(16833): at activities.NotasActivity.agregarNota(NotasActivity.java:52)
    04-14 20:21:00.540: E/AndroidRuntime(16833): … 14 more

    Perdón por el tocho. Un saludo y gracias!

    • Buenas Roberto,

      Al ver el Log que me has pasado, puedes ver que hay varias causas.

      -Caused by: android.content.ActivityNotFoundException: Unable to find explicit activity class {org.example.notas/activities.NuevaNotaActivity}; have you declared this activity in your AndroidManifest.xml?

      Dice que en el AndroidManifest.xml puede que no tengas definida la Activity a la que estás intentando llamar para abrirla.

      startIntentForResult creo que no existe, por lo cual puede que sea otro error (pero el propio IDE debería avisarte subrayandolo en rojo).

      Saludos, espero haber sido de ayuda, cualquier cosa no dudes en preguntar!

  28. Como se tendria que modificar el codigo para que permita modificar las notas, es decir el texto predictivo me cambio una palabra y no lo note y guarde y quisiera cambiarla, seria mas comodo que permita modificarla y no eliminarla y crearla nuevamente, por supuesto sin quitar la opcion de eliminar

    • Buenas Miguel,

      Esta entrada es solo una introducción básica de como crear o eliminar.

      Para actualizar una nota bastaría con implementar el método que ejecute una sentencia «update» sobre la base de datos, pasando como id de la nota en la clausula «where» para que se actualice la nota correspondiente.

      Saludos!

  29. Me sale un problema con la base de datos 😦

    02-01 09:32:05.465 31578-31578/com.prueba.biancamenacho.listviewbd W/dalvikvm﹕ threadid=1: thread exiting with uncaught exception (group=0x41c28700)
    02-01 09:32:05.470 31578-31578/com.prueba.biancamenacho.listviewbd E/AndroidRuntime﹕ FATAL EXCEPTION: main
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.prueba.biancamenacho.listviewbd/com.prueba.biancamenacho.listviewbd.MainActivity}: android.database.sqlite.SQLiteException: no such column: texto (code 1): , while compiling: SELECT _id, texto FROM notas
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2295)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2349)
    at android.app.ActivityThread.access$700(ActivityThread.java:159)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1316)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:176)
    at android.app.ActivityThread.main(ActivityThread.java:5419)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:525)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
    at dalvik.system.NativeStart.main(Native Method)
    Caused by: android.database.sqlite.SQLiteException: no such column: texto (code 1): , while compiling: SELECT _id, texto FROM notas
    at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
    at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:1118)
    at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:691)
    at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
    at android.database.sqlite.SQLiteProgram.(SQLiteProgram.java:58)
    at android.database.sqlite.SQLiteQuery.(SQLiteQuery.java:37)
    at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:44)
    at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1436)
    at android.database.sqlite.SQLiteDatabase.queryWithFactory(SQLiteDatabase.java:1283)
    at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1154)
    at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1322)
    at com.prueba.biancamenacho.listviewbd.NotasDataSource.getAllNotas(NotasDataSource.java:54)
    at com.prueba.biancamenacho.listviewbd.MainActivity.onCreate(MainActivity.java:41)
    at android.app.Activity.performCreate(Activity.java:5372)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1104)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2257)
                at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2349)
                at android.app.ActivityThread.access$700(ActivityThread.java:159)
                at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1316)
                at android.os.Handler.dispatchMessage(Handler.java:99)
                at android.os.Looper.loop(Looper.java:176)
                at android.app.ActivityThread.main(ActivityThread.java:5419)
                at java.lang.reflect.Method.invokeNative(Native Method)
                at java.lang.reflect.Method.invoke(Method.java:525)
                at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)
                at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
                at dalvik.system.NativeStart.main(Native Method)

    • Buenas blanca,

      He probado el código de este ejemplo, y no me aparece el problema.

      Por lo que puedo leer en la excepción, dice que no tienes una columna llamada «texto», Verifica los nombres de las columnas, a la hora de crear la base de datos y a la hora de hacer la sentencia SELECT.

      Saludos!

Replica a Donnie Emanuel Cancelar la respuesta