代码之家  ›  专栏  ›  技术社区  ›  Ragunath Jawahar cephus

Android SQLite内存泄漏

  •  1
  • Ragunath Jawahar cephus  · 技术社区  · 15 年前

    我知道这是一个很长的职位。请不要介意。

    Leak found
    E/Database( 4549): java.lang.IllegalStateException: mPrograms size 1
    E/Database( 4549):  at android.database.sqlite.SQLiteDatabase.finalize(SQLiteDatabase.java:1668)
    E/Database( 4549):  at dalvik.system.NativeStart.run(Native Method)
    E/Database( 4549): Caused by: java.lang.IllegalStateException: /data/data/com.rjblackbox.droid.fvt/databases/fvt.db SQLiteDatabase created and never closed
    E/Database( 4549):  at android.database.sqlite.SQLiteDatabase.<init>(SQLiteDatabase.java:1694)
    E/Database( 4549):  at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:738)
    E/Database( 4549):  at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:760)
    E/Database( 4549):  at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:753)
    E/Database( 4549):  at android.app.ApplicationContext.openOrCreateDatabase(ApplicationContext.java:473)
    E/Database( 4549):  at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:193)
    E/Database( 4549):  at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:98)
    E/Database( 4549):  at com.rjblackbox.droid.fvt.FVTDataHelper.<init>(FVTDataHelper.java:37)
    E/Database( 4549):  at com.rjblackbox.droid.fvt.FVTNotificationService.getNextEntry(FVTNotificationService.java:91)
    E/Database( 4549):  at com.rjblackbox.droid.fvt.FVTNotificationService.access$2(FVTNotificationService.java:90)
    E/Database( 4549):  at com.rjblackbox.droid.fvt.FVTNotificationService$1.run(FVTNotificationService.java:53)
    E/Database( 4549):  at android.os.Handler.handleCallback(Handler.java:587)
    E/Database( 4549):  at android.os.Handler.dispatchMessage(Handler.java:92)
    E/Database( 4549):  at android.os.Looper.loop(Looper.java:123)
    E/Database( 4549):  at android.app.ActivityThread.main(ActivityThread.java:4363)
    E/Database( 4549):  at java.lang.reflect.Method.invokeNative(Native Method)
    E/Database( 4549):  at java.lang.reflect.Method.invoke(Method.java:521)
    E/Database( 4549):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
    E/Database( 4549):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
    E/Database( 4549):  at dalvik.system.NativeStart.main(Native Method)
    

    活动 ,我也有一个 服务 访问数据。对于有经验的开发人员来说,这一定是小菜一碟。

    public class FVTDataHelper {
        private static final String DB_NAME = "fvt.db";
        private static final int DB_VERSION = 1;
    
        private static final String TABLE_TIMERS = "timers";
        private static final String[] TABLE_TIMERS_COLUMNS = {"id", "name", "added", "expires"};
        private static final String TIMER_INSERT = "INSERT INTO " + 
        TABLE_TIMERS + "('name', 'added', 'expires') VALUES (?, ?, ?)";
    
        private SQLiteDatabase db;
        private Cursor c;
        private SQLiteStatement timerInsert;
    
        //Constructor
        public FVTDataHelper(Context ctx) {
            OpenHelper oh = new OpenHelper(ctx);
            db = oh.getWritableDatabase();
            timerInsert = db.compileStatement(TIMER_INSERT);
        }
    
        public void addTimerEntry(TimerEntry entry) {
            String name = entry.getName();
            long added = entry.getAdded();
            long expires = entry.getExpires();
    
            timerInsert.bindString(1, name);
            timerInsert.bindString(2, Long.toString(added));
            timerInsert.bindString(3, Long.toString(expires));
            timerInsert.executeInsert();
        }
    
        public List<TimerEntry> getTimerEntries() {
            ArrayList<TimerEntry> entries = new ArrayList<TimerEntry>();
            c = db.query(TABLE_TIMERS, TABLE_TIMERS_COLUMNS, null, null, null, null, "expires asc");
    
            if(c.moveToFirst()) {
                int id;
                String name;
                long added;
                long expires;
    
                do {
                    id = c.getInt(0);
                    name = c.getString(1);
                    added = c.getLong(2);
                    expires = c.getLong(3);
    
                    if((System.currentTimeMillis() - added) >= 0) {
                        entries.add(new TimerEntry(id, name, added, expires));
                    }
                } while(c.moveToNext());
            }
            c.close();
            return entries;
        }
    
        public void deleteTimerEntry(int id) {
            db.delete(TABLE_TIMERS, "id=" + id, null);
        }
    
        //Helper class for creating and updating database 
        private static class OpenHelper extends SQLiteOpenHelper {
            private Context ctx;
    
            public OpenHelper(Context ctx) {
                super(ctx, DB_NAME, null, DB_VERSION);
                this.ctx = ctx;
            }
    
            @Override
            public void onCreate(SQLiteDatabase db) {
                String sqlDump = getSQLDump();
    
                String[] statements = sqlDump.split("\n");
                for(String statement : statements) {
                    if(DEBUG) Log.d(TAG, statement);
                    db.execSQL(statement);
                }
            }
    
            @Override
            public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
                onCreate(db);
            }
    
            //Helper: Returns SQL statements from the dump
            private String getSQLDump() {
                StringBuilder sb = new StringBuilder();
                try {
                    InputStream is = ctx.getAssets().open("dump.sql");
                    int c;
                    while((c = is.read()) != -1) {
                        sb.append((char) c);
                    }
                    is.close();
                } catch (IOException e) {
                    Log.d(TAG, e.getMessage());
                }
                return sb.length() > 0 ? sb.toString() : ";";
            }
        }
    }
    
    1 回复  |  直到 15 年前
        1
  •  10
  •   Al.    15 年前

    您需要在重新打开数据库之前关闭它,堆栈跟踪消息非常清楚问题所在。

    android.app.Application 类并将开放数据库实例存储在其中。如果这样做,请确保使用 Application 上下文而不是 Activity 否则,当您的活动被破坏时,您可以泄漏上下文。

    另一种解决方案是在onDestroy/onStop等中关闭数据库,然后在onCreate/onStart等中重新打开它。

    推荐文章