从未在数据库上显式调用close()

时间:2012-09-25 07:24:13

标签: android database

我已经完成了没有崩溃的应用程序,但是我在logcat中遇到了这些错误。当我回到第一个活动并从列表视图中选择项目时,它们会出现。我试图关闭游标和数据库。 出了什么问题?

09-25 09:13:07.609: I/dalvikvm(1013): threadid=3: reacting to signal 3
09-25 09:13:07.759: I/dalvikvm(1013): Wrote stack traces to '/data/anr/traces.txt'
09-25 09:13:08.089: I/dalvikvm(1013): threadid=3: reacting to signal 3
09-25 09:13:08.160: I/dalvikvm(1013): Wrote stack traces to '/data/anr/traces.txt'
09-25 09:13:08.579: I/dalvikvm(1013): threadid=3: reacting to signal 3
09-25 09:13:08.629: I/dalvikvm(1013): Wrote stack traces to '/data/anr/traces.txt'
09-25 09:13:23.170: D/dalvikvm(1013): GC_CONCURRENT freed 516K, 6% free 10848K/11463K, paused 27ms+14ms
09-25 09:13:23.209: E/SQLiteDatabase(1013): close() was never explicitly called on database '/data/data/hr.punctum.LociranjePonudaProizvoda/databases/proizvodidb' 
09-25 09:13:23.209: E/SQLiteDatabase(1013): android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here
09-25 09:13:23.209: E/SQLiteDatabase(1013):     at android.database.sqlite.SQLiteDatabase.<init>(SQLiteDatabase.java:1943)
09-25 09:13:23.209: E/SQLiteDatabase(1013):     at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:1007)
09-25 09:13:23.209: E/SQLiteDatabase(1013):     at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:986)
09-25 09:13:23.209: E/SQLiteDatabase(1013):     at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:1051)
09-25 09:13:23.209: E/SQLiteDatabase(1013):     at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:770)
09-25 09:13:23.209: E/SQLiteDatabase(1013):     at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:221)
09-25 09:13:23.209: E/SQLiteDatabase(1013):     at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:157)
09-25 09:13:23.209: E/SQLiteDatabase(1013):     at hr.punctum.LociranjePonudaProizvoda.ListaProizvoda.onCreate(ListaProizvoda.java:27)
09-25 09:13:23.209: E/SQLiteDatabase(1013):     at android.app.Activity.performCreate(Activity.java:4465)
09-25 09:13:23.209: E/SQLiteDatabase(1013):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049)
09-25 09:13:23.209: E/SQLiteDatabase(1013):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1920)
09-25 09:13:23.209: E/SQLiteDatabase(1013):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
09-25 09:13:23.209: E/SQLiteDatabase(1013):     at android.app.ActivityThread.access$600(ActivityThread.java:123)
09-25 09:13:23.209: E/SQLiteDatabase(1013):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
09-25 09:13:23.209: E/SQLiteDatabase(1013):     at android.os.Handler.dispatchMessage(Handler.java:99)
09-25 09:13:23.209: E/SQLiteDatabase(1013):     at android.os.Looper.loop(Looper.java:137)
09-25 09:13:23.209: E/SQLiteDatabase(1013):     at android.app.ActivityThread.main(ActivityThread.java:4424)
09-25 09:13:23.209: E/SQLiteDatabase(1013):     at java.lang.reflect.Method.invokeNative(Native Method)
09-25 09:13:23.209: E/SQLiteDatabase(1013):     at java.lang.reflect.Method.invoke(Method.java:511)
09-25 09:13:23.209: E/SQLiteDatabase(1013):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
09-25 09:13:23.209: E/SQLiteDatabase(1013):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
09-25 09:13:23.209: E/SQLiteDatabase(1013):     at dalvik.system.NativeStart.main(Native Method)
09-25 09:13:23.230: E/System(1013): Uncaught exception thrown by finalizer
09-25 09:13:23.261: E/System(1013): java.lang.IllegalStateException: Don't have database lock!
09-25 09:13:23.261: E/System(1013):     at android.database.sqlite.SQLiteDatabase.verifyLockOwner(SQLiteDatabase.java:2090)
09-25 09:13:23.261: E/System(1013):     at android.database.sqlite.SQLiteDatabase$1.entryRemoved(SQLiteDatabase.java:2182)
09-25 09:13:23.261: E/System(1013):     at android.database.sqlite.SQLiteDatabase$1.entryRemoved(SQLiteDatabase.java:2178)
09-25 09:13:23.261: E/System(1013):     at android.util.LruCache.trimToSize(LruCache.java:197)
09-25 09:13:23.261: E/System(1013):     at android.util.LruCache.evictAll(LruCache.java:285)
09-25 09:13:23.261: E/System(1013):     at android.database.sqlite.SQLiteDatabase.deallocCachedSqlStatements(SQLiteDatabase.java:2143)
09-25 09:13:23.261: E/System(1013):     at android.database.sqlite.SQLiteDatabase.closeClosable(SQLiteDatabase.java:1126)
09-25 09:13:23.261: E/System(1013):     at android.database.sqlite.SQLiteDatabase.finalize(SQLiteDatabase.java:1914)
09-25 09:13:23.261: E/System(1013):     at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:182)
09-25 09:13:23.261: E/System(1013):     at java.lang.Daemons$FinalizerDaemon.run(Daemons.java:168)
09-25 09:13:23.261: E/System(1013):     at java.lang.Thread.run(Thread.java:856)
09-25 09:13:23.390: I/dalvikvm(1013): threadid=3: reacting to signal 3
09-25 09:13:23.409: I/dalvikvm(1013): Wrote stack traces to '/data/anr/traces.txt'

DatabaseHelper.java

package hr.punctum.LociranjePonudaProizvoda;


public class DatabaseHelper extends SQLiteOpenHelper {

    public static final String DATABASE_NAME = "proizvodidb";

    public DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {

        String sql = "CREATE TABLE IF NOT EXISTS proizvodi (" +
                        "_id INTEGER PRIMARY KEY AUTOINCREMENT, " + 
                        "naziv TEXT, " +
                        "tvrtka TEXT, " +
                        "cijena TEXT, " +
                        "kategorija TEXT, " +
                        "telefonTvrtke TEXT, " +
                        "adresaTvrtke TEXT, " +
                        "latitude INTEGER, " +
                        "longitude INTEGER)";

        db.execSQL(sql);

        ContentValues values = new ContentValues();

        values.put("naziv", "Canon 5D mark III");
        values.put("tvrtka", "M-Computers");
        values.put("cijena", "27257kn");
        values.put("kategorija", "fotoaparati");
        values.put("telefonTvrtke", "01/3707800");
        values.put("adresaTvrtke", "Cankareva 3, Zagreb");
        values.put("latitude", 45813029);
        values.put("longitude", 15977894);
        db.insert("proizvodi", "tvrtka", values);

}
@Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS proizvodi");
        onCreate(db);

        db.close();
    }

ListaProizvoda.java

package hr.punctum.LociranjePonudaProizvoda;


public class ListaProizvoda extends ListActivity {

    protected EditText searchText;
    protected SQLiteDatabase db;
    protected Cursor cursor;
    protected ListAdapter adapter;


    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        db = (new DatabaseHelper(this)).getWritableDatabase();
        searchText = (EditText) findViewById (R.id.searchText);

    }    

    @SuppressWarnings("deprecation")

    public void search(View view) {

        cursor = db.rawQuery("SELECT _id, naziv, tvrtka, cijena FROM proizvodi WHERE naziv LIKE ?", 
                        new String[]{searchText.getText().toString() + "%"}); 
        adapter = new SimpleCursorAdapter(this,R.layout.proizvodi_list_artikl,cursor,new String[] {"naziv", "tvrtka", "cijena"},new int[] {R.id.naziv, R.id.tvrtka, R.id.cijena});

        startManagingCursor(cursor);
        setListAdapter(adapter);

    }

    public void onListItemClick(ListView parent, View view, int position, long id) {

        Intent intent = new Intent(getApplicationContext(), DetaljiProizvoda.class);
        Cursor cursor = (Cursor) adapter.getItem(position);
        intent.putExtra("PROIZVODI_ID", cursor.getInt(cursor.getColumnIndex("_id")));
        startActivity(intent);

    }      

}   

DetaljiProizvoda.java

package hr.punctum.LociranjePonudaProizvoda;



public class DetaljiProizvoda extends Activity {

    protected TextView naziv;
    protected TextView kategorija;
    protected TextView tvrtka;
    protected TextView telefonTvrtke;
    protected TextView adresaTvrtke;
    protected int proizvodId;
    protected Cursor cursor; 
    protected ListAdapter adapter; 
    protected SQLiteDatabase db;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.detalji_proizvoda);

        proizvodId = getIntent().getIntExtra("PROIZVODI_ID", 0);
        db = (new DatabaseHelper(this)).getWritableDatabase();
        cursor = db.rawQuery("SELECT proizv._id, proizv.naziv, proizv.tvrtka, proizv.cijena, proizv.kategorija, proizv.telefonTvrtke, proizv.adresaTvrtke, proizv.latitude, proizv.longitude FROM proizvodi proizv LEFT OUTER JOIN proizvodi mgr ON proizv._id = mgr._id WHERE proizv._id = ?", 
                new String[]{""+proizvodId});

        if (cursor.getCount() == 1)
        {
            cursor.moveToFirst();

            naziv = (TextView) findViewById(R.id.naziv);
            naziv.setText(cursor.getString(cursor.getColumnIndex("naziv"))); 

            kategorija = (TextView) findViewById(R.id.kategorija);
            kategorija.setText(cursor.getString(cursor.getColumnIndex("kategorija")));

            tvrtka = (TextView) findViewById(R.id.tvrtka);
            tvrtka.setText(cursor.getString(cursor.getColumnIndex("tvrtka")));

            telefonTvrtke = (TextView) findViewById(R.id.telefonTvrtke);
            telefonTvrtke.setText(cursor.getString(cursor.getColumnIndex("telefonTvrtke")));

            adresaTvrtke = (TextView) findViewById(R.id.adresaTvrtke);
            adresaTvrtke.setText(cursor.getString(cursor.getColumnIndex("adresaTvrtke")));

        }             
    }

      public void changeActivity(View view) { 

            Intent intent = new Intent(getApplicationContext(), GMapsActivity.class);
            intent.putExtra("PROIZVODI_ID", cursor.getColumnIndex("_id"));
            intent.putExtra("PROIZVODI_LATITUDE", cursor.getInt(cursor.getColumnIndex("latitude")));
            intent.putExtra("PROIZVODI_LONGITUDE", cursor.getInt(cursor.getColumnIndex("longitude")));
            startActivity(intent);      

            cursor.close();
            db.close(); 

        }                  

    }   

4 个答案:

答案 0 :(得分:3)

按活动的onStop()onDestroy()方法关闭数据库。

答案 1 :(得分:1)

你应该忘记database.close()。请在您的案例中验证所有 database.open(),并在成功运行后关闭数据库。

答案 2 :(得分:1)

最好将DatabaseHelper变成单例并在应用程序的生命周期内保持打开状态: -

DatabaseHelper helper = DatabaseHelper.getInstance();

这是一种常见的方法,因为您永远不必显式关闭数据库,并且由于Android是单用户环境,因此无需经常打开和关闭数据库。

ContentProvider实现作为单例持久化,并且通常在提供者onCreate(...)中创建SqliteOpenHelper的字段实例,您可以在此处查看它的示例http://developer.android.com/guide/topics/providers/content-provider-creating.html

因此,无论您决定管理数据库生命周期,请考虑在某处保留单个实例以避免遇到麻烦,尤其是当您开始在线程中使用它时。

答案 3 :(得分:0)

在活动的onDestroy

时关闭数据库
protected void onDestroy() 
{
    super.onDestroy();
    if (db != null) 
    {
        db.close();
    }
}

并在datahelper类中添加close方法

public void close() {
        // NOTE: openHelper must now be a member of CallDataHelper;
        // you currently have it as a local in your constructor
        if (openHelper != null) {
            openHelper.close();
        }
    }