J'essaie de copier une base de données que j'ai créée avec le gestionnaire SQLite, dans laquelle j'ai:
CREATE TABLE "Android_metadata" ("locale" TEXT DEFAULT 'en_US')
et
INSERT INTO "Android_metadata" VALUES ('en_US')
Et j'ai nommé toutes mes clés primaires _id
. Ma base de données est copiée (lors de la première exécution, le logcat contient divers messages rouges); par la suite, il ne donne une erreur que lorsque je l'interroge.
Activité principale
public class MainActivity extends Activity {
String CNAME=" ques",TABLE_NAME=" JAVAQ";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Setupdb dbobj=new Setupdb(this);
try {
//dbobj.close();
dbobj.createDataBase();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
dbobj.openDataBase();
dbobj.close();
try{
SQLiteDatabase sqdb=dbobj.getReadableDatabase();
Cursor c = sqdb.query(TABLE_NAME,
new String[] { CNAME },
null, null, null, null, null);
while (c.moveToNext()) {
String name =
c.getString(c.getColumnIndex(CNAME));
Log.i("LOG_TAG", " HAS NAME " + name);
}}
catch(Exception e){
Log.e("err", e.toString());
}
}}
Setupdb
public class Setupdb extends SQLiteOpenHelper {
private static String DB_PATH = "";
private static final String DB_NAME = "camprep.sqlite";
private SQLiteDatabase myDataBase;
private final Context myContext;
private static Setupdb mDBConnection;
public Setupdb(Context context) {
super(context, DB_NAME, null, 3);
this.myContext=context;
DB_PATH="/data/data/"
+ context.getApplicationContext().getPackageName()
+ "/databases/";
Log.e(DB_NAME, DB_PATH);
}
public static synchronized Setupdb getDBAdapterInstance(Context context) {
if (mDBConnection == null) {
mDBConnection = new Setupdb(context);
}
return mDBConnection;
}
public void createDataBase() throws IOException {
boolean dbExist = checkDataBase();
if (dbExist) {
Log.e("db","exist");
// do nothing - database already exist
} else {
// By calling following method
// 1) an empty database will be created into the default system path of your application
// 2) than we overwrite that database with our database.
this.getReadableDatabase();
try {
Log.e("calling", "copy");
copyDataBase();
} catch (IOException e) {
throw new Error("Error copying database");
}
}
}
private boolean checkDataBase() {
SQLiteDatabase checkDB = null;
try {
String myPath = DB_PATH + DB_NAME;
checkDB = SQLiteDatabase.openDatabase(myPath, null,
SQLiteDatabase.OPEN_READONLY);
} catch (SQLiteException e) {
// database does't exist yet.
}
if (checkDB != null) {
checkDB.close();
}
return checkDB != null ? true : false;
}
private void copyDataBase() throws IOException {
// Open your local db as the input stream
InputStream myInput = myContext.getAssets().open(DB_NAME);
// Path to the just created empty db
String outFileName = DB_PATH + DB_NAME;
// Open the empty db as the output stream
OutputStream myOutput = new FileOutputStream(outFileName);
// transfer bytes from the inputfile to the outputfile
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
// Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
}
public void openDataBase() throws SQLException {
String myPath = DB_PATH + DB_NAME;
myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE);
}
public synchronized void close() {
if (myDataBase != null)
myDataBase.close();
super.close();
}
@Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
Trace de la pile
08-31 20:17:05.320: I/dalvikvm(9457): threadid=3: reacting to signal 3
08-31 20:17:05.370: I/dalvikvm(9457): Wrote stack traces to '/data/anr/traces.txt'
08-31 20:17:05.451: E/camprep.sqlite(9457): /data/data/com.example.mydataexplosion/databases/
08-31 20:17:05.490: E/db(9457): exist
08-31 20:17:05.521: E/CursorWindow(9457): Failed to read row 0, column -1 from a CursorWindow which has 11 rows, 1 columns.
08-31 20:17:05.521: E/err(9457): Java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.
08-31 20:17:05.650: D/gralloc_goldfish(9457): Emulator without GPU emulation detected.
08-31 20:17:05.650: I/dalvikvm(9457): threadid=3: reacting to signal 3
08-31 20:17:05.670: I/dalvikvm(9457): Wrote stack traces to '/data/anr/traces.txt'
si tu vois
failed to read row 0,column -1
Cela signifie que vous essayez de lire une colonne qui n'existe pas.
S'il ne parvient pas à trouver le nom de la colonne que vous spécifiez, Cursor.getColumnIndex()
renvoie -1
et, par conséquent, n'est pas valide.
Il y a deux raisons à cela:
Remarque: le nom de la colonne est CASE SENSITIVE en utilisant getColumnIndex()
Dans votre scénario:
c.getString(c.getColumnIndex(CNAME));
Vérifiez que la variable CNAME est correctement orthographiée et qu’une colonne de ce nom existe.
String CNAME=" ques"
Cet espace blanc supplémentaire doit-il être présent, par exemple?.
Avant de commencer à lire les valeurs consécutives à l'aide de c.moveToNext()
, positionnez le curseur sur la position initiale, c'est-à-dire le début de votre base de données.
c.moveToFirst()
et puis commencez à le lire.
Peut résoudre votre problème.
L'erreur consistait à utiliser les trémas ü, ö, ä dans les noms de colonne de la base de données.
Bien que vous puissiez obtenir le contenu en changeant avec la méthode cursor.movetonext()
aussi souvent jusqu'à ce que vous passiez au bon numéro, c'était très ennuyeux et vous demandait beaucoup de code.
Je suppose que cela devrait résoudre les problèmes pour la plupart d'entre vous. Je suppose que tout sauf ASCII est faux - les espaces, les points, les inconvénients, etc., ne peuvent pas être utilisés non plus.
Vous pouvez créer avec succès une base de données et voir à l’aide d’outils SQLite externes, mais Android agira toujours.
Un autre scénario où cela peut arriver:
Vous supprimez des lignes du curseur alors qu'il est encore utilisé.
Pseudo-coden où cela pourrait arriver:
while(cursor.moveToNext()){
readCursor(cursor);
deleteRowFromCursor(cursor);
}
Solution:
Gardez la liste des lignes que vous souhaitez supprimer. construire une instruction sql de suppression par lots; exécutez la déclaration en dehors de la boucle while (lorsque vous avez terminé d'utiliser le curseur ou après l'avoir fermée).
while(cursor.moveToNext()){
readCursor(cursor);
queueRowForDelete(cursor);
}
deleteQueuedRows(queuedRowsList);