PDA

Ver la Versión Completa : [ CONSULTA ] Error SQLite


marellanor
23/08/14, 01:36:39
La primera vez que compilo e ingreso al activity donde seteo y leo datos a la BD, me ingresa datos a la BD y los me los muestra. Cuando intento ingresar nuevamente al activity me bota la aplicación. Solo funciona (una vez) cuando le cambio la versión de la BD en el constructor.

Alguien me podría ayudar con el error?

Saludos y gracias!.

Activity
package com.paquete.juegayaprendeapp;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class ScoreJuego2 extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.scorejuego2);

//Acá seteo el nombre del layout
this.setTitle("Puntajes Juego 2");

Handler_sqlite helper = new Handler_sqlite(this);

TextView tv1 = (TextView) findViewById(R.id.plugarj2);
TextView tv2 = (TextView) findViewById(R.id.slugarj2);
TextView tv3 = (TextView) findViewById(R.id.tlugarj2);

//helper.abrirdb();

helper.insertarReg("pepe1", "3");
helper.insertarReg("pepe2", "2");
helper.insertarReg("pepe3", "1");

String temp[] = helper.leer();

tv1.setText(""+temp[0]);
tv2.setText(""+temp[1]);
tv3.setText(""+temp[2]);

helper.cerrardb();
}

}


Clase BaseDatos

package com.paquete.juegayaprendeapp;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFacto ry;
import android.database.sqlite.SQLiteOpenHelper;

import static android.provider.BaseColumns._ID;

public class Handler_sqlite extends SQLiteOpenHelper {

public Handler_sqlite(Context ctx) {
super(ctx, "Base2", null, 1);

}

@Override
public void onCreate(SQLiteDatabase db) {

String query = "CREATE TABLE juego2 ("+ _ID +" INTEGER PRIMARY KEY AUTOINCREMENT," +
"jugador TEXT, puntos TEXT); ";

db.execSQL(query);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

db.execSQL("DROP TABLE IF EXISTS juego2");
onCreate(db);

}

public void insertarReg(String usr, String pnts){

ContentValues valores = new ContentValues();
valores.put("jugador", usr);
valores.put("puntos", pnts);
this.getWritableDatabase().insert("juego2", null, valores);

}

public String[] leer(){

String result[] = new String [3];
String columnas[] = {_ID, "jugador", "puntos"};
Cursor c = this.getReadableDatabase().query("juego2", columnas, null, null, null, null, null, null);

int id, iu, ip;

id = c.getColumnIndex(_ID);
iu = c.getColumnIndex("jugador");
ip = c.getColumnIndex("puntos");

int contador=0;
for(c.moveToFirst();!c.isAfterLast();c.moveToNext( )){

result[contador] = c.getString(id)+" "+c.getString(iu)+" "+c.getString(ip) +"\n";
contador++;
}

return result;
}

public void abrirdb(){
this.getWritableDatabase();
}

public void cerrardb(){
this.close();
}


}

kriogeN
23/08/14, 02:00:59
Al ejecutar la segunda vez la aplicación vuelves a ejecutar esto:

helper.insertarReg("pepe1", "3");
helper.insertarReg("pepe2", "2");
helper.insertarReg("pepe3", "1");

Y por tanto tu base de datos pasa a tener 6 registros (3 duplicados).

Después ejecutas esto:

int contador=0;
for(c.moveToFirst();!c.isAfterLast();c.moveToNext( )){

result[contador] = c.getString(id)+" "+c.getString(iu)+" "+c.getString(ip) +"\n";
contador++;
}

Habiendo establecido que el Array Result tiene un tamaño de 3, pero como tu BD tiene 6 registros el for querrá hacer los 6 registros, así que cuando va a hacer:

result[contador] = c.getString(id)+" "+c.getString(iu)+" "+c.getString(ip) +"\n";

con contador=3 te da un ArrayOutOfBoundException, porque estás intentando meter una 4ª posición en un Array que tiene 3.

Soluciones:

1) No vuelvas a meter lo mismo 2 veces, o al menos controla lo que metes en la BD
2) En vez de un Array de tamaño fijo usa un ArrayList que tiene tamaño dinámico.

marellanor
23/08/14, 02:22:29
Agradeciendo tu respuesta, tengo otra pregunta al respecto. ¿Por qué solo funciona al cambiar el número de versión a uno siguiente, si es que lo volví a compilar? ¿Al compilar de nuevo no se crea todo de nuevo? y cómo se podría controlar desde el activity, que sólo se ingresen esos 3 registros y nada mas?.

Saludos y Gracias!

kriogeN
23/08/14, 10:49:14
Las bases de datos SQLite tienen como propósito que los datos de la aplicación se mantengan entre ejecuciones, incluso si creas una versión nueva de la aplicación y la instalas que se sigan manteniendo. Por eso si vuelves a compilar e instalar la app los datos siguen estando.

Pero si cambias el número de la versión se ejecuta el proceso onUpgrade de la base de datos, que en este caso lo que hace es destruir la BD y volverla a crear, y por tanto eliminar los registros.

Si sólo quieres que tu app tenga esos 3 registros y ninguno más puedes hacerlo de 2 formas:
1) Introducir los registros en el onCreate de la BD, así sólo se ejecutará cuando la BD se cree la primera vez (o se actualice)
2) Antes de introducir los registros consultrar si la BD ya tiene registros.

marellanor
23/08/14, 20:48:07
Ahora me queda super claro. Muchas gracias por tu respuesta.
Ahora acotando a las 2 opciones que me das para solucionar el problema.
En el hito 1: Debería ser así?

@Override
public void onCreate(SQLiteDatabase db) {

String query = "CREATE TABLE juego2 ("+_ID+" INTEGER PRIMARY KEY," +
"jugador TEXT, puntos TEXT); ";

db.execSQL(query);

String query2="INSERT INTO juego2 (jugador, puntos)" +
"VALUES("pepeito", "1");";

db.execSQL(query2);

}


Y la segunda opción, tú como lo harías?.

Saludos y Gracias!!