Android SQLite 内存泄漏

2024-02-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)

这是我的内存泄漏的堆栈跟踪。下面是我的数据助手的源代码。除了一个Activity,我也有一个Service访问数据。对于经验丰富的开发人员来说,这一定是小菜一碟。

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() : ";";
        }
    }
}

您需要先关闭数据库,然后才能重新打开它,堆栈跟踪消息非常清楚地表明问题所在。

一种解决方案是利用android.app.Application类并将打开的数据库实例存储在其中。如果这样做,请务必使用以下命令打开数据库Application上下文而不是Activity否则,当您的活动被销毁时,您可能会泄漏上下文。

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android SQLite 内存泄漏 的相关文章

  • 在 Anko DSL 中创建自定义 View/ViewGroup 类

    我想创建一个自定义视图 它只是一些 Android 视图的包装 我考虑创建一个自定义 ViewGroup 来管理其子视图的布局 但我不需要这么复杂 我基本上想做的是 class MainActivity verticalLayout tex
  • 如何在 SQL Server 2012 中选择除一列之外的所有列? [复制]

    这个问题在这里已经有答案了 有没有一种方法可以选择所有列 但只选择我不想选择的特定列 我的意思是有时我会遇到这样的问题 表有数百个字段 而我只需要删除一个字段 我需要重写所有列吗 有什么窍门吗 喜欢select
  • 在 Android 中长按时从操作模式中删除后退/主页按钮

    我已经在里面长按实现了上下文操作模式recycler view 为此我打电话给ActionModeCallback从创建动作模式开始 创建动作模式时 默认显示后退箭头 检查如下 单击后退箭头 操作模式将关闭 现在我想要hide or rem
  • hive - 在值范围之间将一行拆分为多行

    我在下面有一张表 想按从开始列到结束列的范围拆分行 即 id 和 value 应该对开始和结束之间的每个值重复 包括两者 id value start end 1 5 1 4 2 8 5 9 所需输出 id value current
  • Android:应用内计费V3超时返回哪个响应码?

    出现网络超时情况时 Google Play 应用内结算服务 ice er V3 将返回哪些响应状态代码 它的所有功能都是统一的吗 我将在这里描述我的发现 我通过拔掉主机插头 在安装了全功能 GP GP Store V3 10 10 GP S
  • 如何查看 Android 上的 Wi-Fi 是否已连接?

    我什至不希望我的用户尝试下载某些内容 除非他们连接了 Wi Fi 然而 我似乎只能判断是否启用了 Wi Fi 但他们仍然可以有 3G 连接 android net wifi WifiManager m WifiManager getSyst
  • 在 Yii 的标准中如何获得计数 (*)

    我正在尝试构建一个具有以下内容的查询group by属性 我正在尝试得到id和count它一直告诉我count is invalid列名 我怎样才能得到count来自group by询问 工作有别名 伊伊 1 1 11 其他不及格 crit
  • 如何持续更新MPAndroidChart中的Y轴值

    我希望 LineChart 中的轴能够实时调整其最大值和最小值 当新数据的 Y 值增加 正值和负值 时 像 ResetAxisMaxValue 和 ResetAxisMinValue 这样的函数可以很好地工作 但是 一旦信号再次变低 Y 值
  • 在 Jetpack Compose 中跨可组合函数重复使用一组预览注释

    在 Jetpack Compose 中迈出第一步 这非常令人惊奇 除了一个恼人的问题 我有一组固定的预览 正常 深色和 RTL Preview name Normal group Screen showBackground true Pre
  • 为什么Android应用程序在发布到市场后尺寸会增加?

    我最近在 Android 市场上发布了我的应用程序 显示应用程序大小为 5 4MB 而实际 apk 大小为 2 8MB 为什么显示多出2MB 我应该如何限制我的应用程序大小 请帮我 您的应用程序大小会增加 因为您使用了复制保护选项ON在发布
  • Android - 如何更改 TimePicker 中的文本颜色?

    我正在使用 TimePicker 到 LinearLayout 中 背景颜色 黑色 但是 我看不到 TimePicker 中的数字 并且我需要在布局中将背景颜色设置为黑色 如何更改 TimePicker 中的 textColor 我已经尝试
  • onBackPressed 隐藏 不破坏 Activity

    我知道如何取消后退按键 以便活动 主窗口保持可见 public void onBackPressed return 我的目标是隐藏该活动 但是 在没有完成它的情况下 您如何在 onBackPressed 事件中做到这一点 即我想达到 onP
  • android httprequest java.net.UnknownHostException

    我想用android发出http请求 是使用这个 void testHTTP HttpClient httpClient new DefaultHttpClient HttpUriRequest request new HttpPost h
  • SQL Server:如果存在会大大减慢查询速度

    正在使用SQL Server 2012 我找到了一些关于查询优化的主题 并将 EXISTS 与 COUNT 进行比较 但我找不到这个确切的问题 我有一个看起来像这样的查询 select from tblAccount as acc join
  • 在 Honeycomb Android 3.0 中显示 Action Bar 菜单项的图标

    我正在使用 Honeycomb android 3 0 开发 Android 应用程序 我正在尝试在 Action Bar 中显示菜单 菜单有一个图标和标题 当我们单击菜单项时 它会以下拉列表的形式显示其项目 它是下拉列表中带有项目名称但不
  • Oracle REGEXP_INSTR() 和“a-z”字符范围与预期不匹配

    我想用REGEXP INSTR 在 oracle 数据库中检查小写 大写字符 我知道 upper and lower POSIX 字符类 但我选择了a z这给了我非常奇怪的结果 我不明白 有人可以解释一下吗 SELECT REGEXP IN
  • FCM onMessageReceived 应用程序运行时返回空白消息和标题

    正如您在标题中所写 当应用程序关闭时 它运行良好 并且onMessageReceived获取消息正文和标题 但如果应用程序处于前台模式 运行模式 则可以发送通知 但没有消息和标题 请问该怎么办 代码 Override public void
  • 安卓的限制

    我需要构建一个应用程序 该应用程序拍摄相机图像并将其上传到网络 在网络上进行一些处理并返回真 假 我在这方面遇到了一些问题 希望得到澄清 1 我的应用程序有什么方法可以知道 Android 相机捕获的图像吗 我从这里明白了什么 Androi
  • Android 自定义警报对话框中的 OnClickListener

    我是一个自学成才的初学者 感谢耐心 谢谢 在 Eclipse 中 我使用自己的 xml 文件 custom dialog 创建了一个自定义警报对话框 称为 usernamealert 如果用户尚未输入用户名 即 username lengt
  • Android:如何检测手机设置中的语言已更改

    我如何检测我的手机语言是否已更改 例如 Facebook 应用程序将向我们宣布 please wait we preparing your language i used myString Locale getDefault getDisp

随机推荐