Android piensa que no estoy cerrando mi base de datos! ¿Por qué?

Tengo un miembro de los datos de SQLiteDatabase que inicializo encendido onCreate y llamo .close () encendido en onPause (), onStop (), y onDestroy (). Se reinicializa en onResume (). Parece correr muy bien, pero cuando miré el depurador que ver esto:

08-24 20:23:50.014: ERROR/Database(6767): Leak found 08-24 20:23:50.014: ERROR/Database(6767): java.lang.IllegalStateException: /data/data/com.hh.Timepunch/databases/times_database.db SQLiteDatabase created and never closed 08-24 20:23:50.014: ERROR/Database(6767): at android.database.sqlite.SQLiteDatabase.<init>(SQLiteDatabase.java:1695) 08-24 20:23:50.014: ERROR/Database(6767): at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:739) 08-24 20:23:50.014: ERROR/Database(6767): at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:761) 08-24 20:23:50.014: ERROR/Database(6767): at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:754) 08-24 20:23:50.014: ERROR/Database(6767): at android.app.ApplicationContext.openOrCreateDatabase(ApplicationContext.java:476) 08-24 20:23:50.014: ERROR/Database(6767): at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:193) 08-24 20:23:50.014: ERROR/Database(6767): at com.hh.Timepunch.TimeSheetActivity.onCreate(TimeSheetActivity.java:72) 08-24 20:23:50.014: ERROR/Database(6767): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047) 08-24 20:23:50.014: ERROR/Database(6767): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2459) 08-24 20:23:50.014: ERROR/Database(6767): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2512) 08-24 20:23:50.014: ERROR/Database(6767): at android.app.ActivityThread.access$2200(ActivityThread.java:119) 08-24 20:23:50.014: ERROR/Database(6767): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1863) 08-24 20:23:50.014: ERROR/Database(6767): at android.os.Handler.dispatchMessage(Handler.java:99) 08-24 20:23:50.014: ERROR/Database(6767): at android.os.Looper.loop(Looper.java:123) 08-24 20:23:50.014: ERROR/Database(6767): at android.app.ActivityThread.main(ActivityThread.java:4363) 08-24 20:23:50.014: ERROR/Database(6767): at java.lang.reflect.Method.invokeNative(Native Method) 08-24 20:23:50.014: ERROR/Database(6767): at java.lang.reflect.Method.invoke(Method.java:521) 08-24 20:23:50.014: ERROR/Database(6767): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860) 08-24 20:23:50.014: ERROR/Database(6767): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618) 08-24 20:23:50.014: ERROR/Database(6767): at dalvik.system.NativeStart.main(Native Method) 08-24 20:23:50.054: ERROR/Database(6767): Leak found 08-24 20:23:50.054: ERROR/Database(6767): java.lang.IllegalStateException: /data/data/com.hh.Timepunch/databases/times_database.db SQLiteDatabase created and never closed 08-24 20:23:50.054: ERROR/Database(6767): at android.database.sqlite.SQLiteDatabase.<init>(SQLiteDatabase.java:1695) 08-24 20:23:50.054: ERROR/Database(6767): at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:739) 08-24 20:23:50.054: ERROR/Database(6767): at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:761) 08-24 20:23:50.054: ERROR/Database(6767): at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:754) 08-24 20:23:50.054: ERROR/Database(6767): at android.app.ApplicationContext.openOrCreateDatabase(ApplicationContext.java:476) 08-24 20:23:50.054: ERROR/Database(6767): at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:193) 08-24 20:23:50.054: ERROR/Database(6767): at com.hh.Timepunch.TimepunchActivity.onCreate(TimepunchActivity.java:60) 08-24 20:23:50.054: ERROR/Database(6767): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047) 08-24 20:23:50.054: ERROR/Database(6767): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2459) 08-24 20:23:50.054: ERROR/Database(6767): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2512) 08-24 20:23:50.054: ERROR/Database(6767): at android.app.ActivityThread.access$2200(ActivityThread.java:119) 08-24 20:23:50.054: ERROR/Database(6767): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1863) 08-24 20:23:50.054: ERROR/Database(6767): at android.os.Handler.dispatchMessage(Handler.java:99) 08-24 20:23:50.054: ERROR/Database(6767): at android.os.Looper.loop(Looper.java:123) 08-24 20:23:50.054: ERROR/Database(6767): at android.app.ActivityThread.main(ActivityThread.java:4363) 08-24 20:23:50.054: ERROR/Database(6767): at java.lang.reflect.Method.invokeNative(Native Method) 08-24 20:23:50.054: ERROR/Database(6767): at java.lang.reflect.Method.invoke(Method.java:521) 08-24 20:23:50.054: ERROR/Database(6767): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860) 08-24 20:23:50.054: ERROR/Database(6767): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618) 08-24 20:23:50.054: ERROR/Database(6767): at dalvik.system.NativeStart.main(Native Method) 08-24 20:23:50.199: ERROR/libs3c2drender(1912): int S3c2DRender::DoG2D(unsigned int, s3c_img*, s3c_rect*, unsigned int, s3c_img*, s3c_rect*, int, int)::S3C_G2D_ROTATOR_18176 fail 

Uno de los lugares en los que obtengo este error es al salir de esta actividad:

 public class TimepunchActivity extends Activity { Calendar timeNow = Calendar.getInstance(); SQLiteDatabase timesDatabase; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.timepunch); //Create/open and configure database (if necessary) timesDatabase = openOrCreateDatabase( "times_database.db", SQLiteDatabase.CREATE_IF_NECESSARY, null); timesDatabase.setLocale(Locale.getDefault()); timesDatabase.setLockingEnabled(false); timesDatabase.setVersion(3); //lenient is set to true so incrementing minute 59 auto increments hour, etc timeNow.setLenient(true); //Create table (if necessary) final String dbCommand = "CREATE TABLE IF NOT EXISTS Timepunches (punch INTEGER PRIMARY KEY);"; timesDatabase.execSQL(dbCommand); updateLastInPunch(); Button punchButton = (Button)findViewById(R.id.punch_button); punchButton.setHapticFeedbackEnabled(true); punchButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { //Insert data ContentValues punchValue = new ContentValues(); punchValue.put("punch", timeNow.getTimeInMillis()); long newPunchID = timesDatabase.insert("Timepunches", null, punchValue); punchValue.clear(); //if punch already exists if (newPunchID < 0) { AlertDialog.Builder builder = new AlertDialog.Builder(TimepunchActivity.this); builder.setTitle("Whoops") .setMessage("I've already recorded a punch for this time and day.") .setCancelable(true) .setNeutralButton("Oh", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }) .show(); } else { } } //end setOnClick() }); //end click listener for punchButton } //end onCreate() @Override public void onResume() { super.onResume(); checkFirstTimer(); //Open and configure database timesDatabase = openOrCreateDatabase( "times_database.db", SQLiteDatabase.CREATE_IF_NECESSARY, null); timesDatabase.setLocale(Locale.getDefault()); timesDatabase.setLockingEnabled(false); timesDatabase.setVersion(3); //Update date object for current time timeNow.setTimeInMillis(System.currentTimeMillis()); timeNow.set(Calendar.SECOND, 0); timeNow.set(Calendar.MILLISECOND, 0); updateClock((TextView)findViewById(R.id.current_time_textbox), timeNow); updateLastInPunch(); } //end onResume() @Override public void onPause() { super.onPause(); timesDatabase.close(); } //end onResume() @Override public void onStop() { super.onStop(); timesDatabase.close(); } //end onResume() @Override public void onDestroy() { super.onDestroy(); timesDatabase.close(); } //end onResume() //Shows last in-punch that has no out-punch // if there is none it hides the section public void updateLastInPunch() { Cursor punchCursor = timesDatabase.query("Timepunches", null, null, null, null, null, "punch ASC;"); TextView inPunchLabel = (TextView)findViewById(R.id.in_punch_label_textview); TextView inPunchTV = (TextView)findViewById(R.id.in_punch_time_textview); //odd count means there is a missing punch (assumed to be latest in punch) // therefore show last in punch if ((punchCursor.getCount()%2) != 0) { punchCursor.moveToLast(); Calendar lastIn = Calendar.getInstance(); lastIn.setTimeInMillis(punchCursor.getLong(0)); updateClock((TextView)findViewById(R.id.in_punch_time_textview), lastIn); inPunchLabel.setVisibility(View.VISIBLE); inPunchLabel.setAnimation(fadeInAnimation); inPunchLabel.startAnimation(fadeInAnimation); inPunchTV.setVisibility(View.VISIBLE); inPunchTV.setAnimation(fadeInAnimation); inPunchTV.startAnimation(fadeInAnimation); } else { //only fade when "turning off" last punch display // (don't fade away when returning to screen) if (inPunchLabel.getVisibility() == View.VISIBLE) { inPunchLabel.setAnimation(fadeOutAnimation); inPunchLabel.startAnimation(fadeOutAnimation); inPunchLabel.setVisibility(View.INVISIBLE); inPunchTV.setAnimation(fadeOutAnimation); inPunchTV.startAnimation(fadeOutAnimation); inPunchTV.setVisibility(View.INVISIBLE); } } punchCursor.close(); } //end getLastInPunch() } //end TimepunchActivity 

Lo extraño es, sin embargo, es que este error no es persistente.

¿Tengo que hacer más que llamar a .close ()?

El problema es que lo estás creando / abriendo en onCreate y luego enResume, así que lo estás haciendo dos veces. Del mismo modo, lo está cerrando dos veces, por lo que probablemente se estrellará.

En general, ¿por qué no utiliza SQLiteOpenHelper ? Esto hará que la gestión de su base de datos mucho más fácil.

En apoyo del punto de EboMike, mira el ciclo de vida de la actividad de Android y el problema con tu código será obvio.

  • La manera más rápida y eficiente de pre-poblar la base de datos en Android
  • SQLite - ¿Es posible insertar un BLOB a través de la instrucción insert?
  • Consulta de eliminación de Android
  • Uso del patrón de diseño Singleton para SQLiteDatabase
  • Establecer un valor predeterminado en una columna en SQLite
  • Cómo probar la actualización de la base de datos sqlite antes de cargar la nueva versión de mi aplicación en la tienda de juegos en android
  • Cómo ejecutar una consulta con regexp en Android
  • Android sqlite cómo comprobar si existe un registro
  • ¿Cómo recuperar datos de un cursor en android?
  • Excepción SQLite: la base de datos está bloqueada
  • Android ExpandableListActivity y SimpleCursorTreeAdapter?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.