为啥 PhoneGap Android 应用程序在将一堆数据插入 SQL 时崩溃?

Posted

技术标签:

【中文标题】为啥 PhoneGap Android 应用程序在将一堆数据插入 SQL 时崩溃?【英文标题】:Why is PhoneGap Android app crashing while inserting bunch of data into SQL?为什么 PhoneGap Android 应用程序在将一堆数据插入 SQL 时崩溃? 【发布时间】:2011-09-11 14:40:37 【问题描述】:

我有在 android 中运行的 PhoneGap 应用。当应用程序启动时,它会在 SQL 中插入大约 500 行。表有 10 列。这不是很多数据,我在文本文件中有一个 JSON,它的大小约为 120 kB。我认为这根本无法触及任何限制,但可能存在一些我不知道的限制,或者可能是 Android 中的错误,因为同一个应用程序在某些版本的 Android(2.2)上运行没有问题,但立即崩溃或者在其他版本的 Android(1.6、2.1、一些 2.3 可能更多......)上使用 SQL 数据库时,在几分钟内

这是我用来填充在 Android 1.6 上崩溃的数据库的代码:

db = window.openDatabase("db", "1.0", "Description", 1000000); 
$.get('db/app_data.dat',function(result)
  var data = $.parseJSON(result);
  try 
    db.transaction(function(tx)
      $.each(data.items, function(i, v)
        try 
          tx.executeSql('INSERT INTO table(c1,c2,c3, ...) VALUES (?,?,?, ...)',[v.c1, v.c2, v.c3, ...]);
         catch(e) 
          alert(e.message);
        
      );
    );
   catch(e) 
    alert(e.message);
    return;
  
);

谁能帮帮我?有一些我不知道的限制吗?还是我在 SQL 数据库中插入数据时做错了什么?

编辑:

这是 LogCat 的输出,我认为这些是应用程序崩溃时日志中的一些重要行。但是,我对 Java 和 Android 没有更深入的了解:

WARN/dalvikvm(1525): ReferenceTable overflow (max=512)
WARN/dalvikvm(1525): Last 10 entries in JNI local reference table:
WARN/dalvikvm(1525):   502: 0x4375cbb8 cls=Ljava/lang/String; (28 bytes)
WARN/dalvikvm(1525):   503: 0x4374c9a0 cls=Ljava/lang/String; (28 bytes)
WARN/dalvikvm(1525):   504: 0x4377c5c0 cls=Ljava/lang/String; (28 bytes)
WARN/dalvikvm(1525):   505: 0x437c3040 cls=Ljava/lang/String; (36 bytes)
WARN/dalvikvm(1525):   506: 0x43760bd8 cls=Ljava/lang/String; (28 bytes)
WARN/dalvikvm(1525):   507: 0x437625e8 cls=Ljava/lang/String; (28 bytes)
WARN/dalvikvm(1525):   508: 0x43762608 cls=Ljava/lang/String; (28 bytes)
WARN/dalvikvm(1525):   509: 0x43762628 cls=Ljava/lang/String; (28 bytes)
WARN/dalvikvm(1525):   510: 0x43759178 cls=Ljava/lang/String; (28 bytes)
WARN/dalvikvm(1525):   511: 0x43766808 cls=Landroid/webkit/WebViewCore; (116 bytes)
ERROR/dalvikvm(1525): Failed adding to JNI local ref table (has 512 entries)
INFO/dalvikvm(1525): "WebViewCoreThread" prio=5 tid=15 RUNNABLE
INFO/dalvikvm(1525):   | group="main" sCount=0 dsCount=0 s=N obj=0x437668a0 self=0x1b0bd0
INFO/dalvikvm(1525):   | sysTid=1532 nice=0 sched=0/0 handle=1772784
INFO/dalvikvm(1525):   at android.webkit.LoadListener.nativeFinished(Native Method)
INFO/dalvikvm(1525):   at android.webkit.LoadListener.tearDown(LoadListener.java:1076)
INFO/dalvikvm(1525):   at android.webkit.LoadListener.handleEndData(LoadListener.java:642)
INFO/dalvikvm(1525):   at android.webkit.LoadListener.handleMessage(LoadListener.java:203)
INFO/dalvikvm(1525):   at android.os.Handler.dispatchMessage(Handler.java:99)
INFO/dalvikvm(1525):   at android.os.Looper.loop(Looper.java:123)
INFO/dalvikvm(1525):   at android.webkit.WebViewCore$WebCoreThread.run(WebViewCore.java:471)
INFO/dalvikvm(1525):   at java.lang.Thread.run(Thread.java:1060)
ERROR/dalvikvm(1525): VM aborting
DEBUG/Zygote(30): Process 1525 terminated by signal (11)

【问题讨论】:

崩溃中的 logcat 或堆栈跟踪肯定会有所帮助。但我认为问题可能有所不同。如果这是在 UI 线程上而不是在其自己的线程中运行,系统可能会认为您的应用已退出响应并终止它。 好的,我已经添加了LogCat的输出,希望对解决这个问题有所帮助。 设置此特定数据库时,它设置为包含 512 个条目。我相信您正在成为一个非常常见的编程错误的受害者。 512 个条目的条目行将从 0 到 511。我认为您从 1 开始。我无法从您的代码中看出,但您的 logcat 说您的 db runneth over。 好吧,我肯定在创建表时没有设置任何限制。我只是在我粘贴在这里的代码之前运行这个命令。 tx.executeSql('CREATE TABLE table_name(id INTEGER, name, time INT, ...)'); @Frodik 你有没有遇到过解决方案或解决方案?谢谢 【参考方案1】:

Phobos 的回答包含一些相关信息,但不包括它如何应用于您的问题或如何解决您的特定问题。我在 android javascript 中进行一些性能测试时遇到了类似的问题,该测试通过使用 addJavascriptInterface 绑定到 webview 上下文中的对象调用 java。虽然我没有明确使用 JNI,但显然在幕后绑定接口使用 JNI 来编组数据 - 我收到了一个类似于你的错误和堆栈跟踪。显然,webDB 或 localStorage 或任何你在那里做的事情也在幕后使用 JNI。

根据 Phobos 链接的信息,当您使用 JNI 时,您可以在范围内拥有的引用数量是有限的。对于间接使用 JNI 的 javascript,似乎必须根据 javascript 范围保留引用。查看您的代码,我不确定您正在做什么以超出限制,但看起来它可能是您在整个事务中进行的调用次数,或者您的值数组最终有超过 512 个元素。如果您需要保持事务完整性并且您确实有超过 500 次操作,那么您可能会不走运。但是,我怀疑您应该能够通过重写代码以在 tx.executeSql 调用范围之外构建查询字符串来找到避免 512 限制的方法。

也许您可以重写代码来构建查询字符串,然后在匿名函数包装器中实际调用tx.executeSql?您可能需要构建包含值的字符串,而不是使用 'INSERT INTO table() VALUES()',[] 语法...正如我上面所说,如果您在事务中有超过 500 个操作,您可能仍然会遇到麻烦,但值得一试!

附:作为参考,这是我的代码的一个版本,它与修复一起崩溃:

var test = function() 
    var a = "a";
    for(i=0;i<1000;i++) 
        boundJavaObj.test(a);
    

test() 崩溃并出现如下错误:

03-28 10:57:45.634: W/dalvikvm(21294): ReferenceTable overflow (max=512)

var test2 = function() 
    var a = "a";
    for(i=0;i<1000;i++) 
        (function()boundJavaObj.test(a);)();
    

test2() 不会崩溃。

【讨论】:

【参考方案2】:

也许你需要一个这样的递归回调函数:

//too many insert statements
var sqlits= ["INSERT INTO ...", .. .. .. ,"INSERT INTO ..."];

function populate()
    db.transaction(function(tx)
        if(sqlits.length > 0)
            sql=sqlits.shift();
            tx.executeSql(sql);
        else
            alert('End');
        
        return true;
    ,function(tx,err) 
        console.log("SQL Error: "+err); 
    ,populate);
;

populate();

【讨论】:

【参考方案3】:

好的。找到了答案。这是 512 个 local 引用的限制。您需要做的是使用 NewGlobalRef() 将它们转换为全局引用,或者很快清理本地 如果不需要它们,则在创建它们之后。但是,将它们更改为全局引用会泄漏内存。

查看this 线程以了解有关此已知问题的更多信息。

【讨论】:

好吧,但是在我的代码中我没有创建任何变量,所以我不知道该怎么做。您的回答不是很有帮助,主要是因为我在 Phonegap 中使用 Javascript 而不是 Java 本身(在您的示例和链接中使用)

以上是关于为啥 PhoneGap Android 应用程序在将一堆数据插入 SQL 时崩溃?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 PhoneGap Android 应用程序在将一堆数据插入 SQL 时崩溃?

PhoneGap - 为啥 Android 虚拟设备不显示更改?

为啥 cordova-local-notification-plugin 不起作用(Phonegap,Android)?

为啥我的 PhoneGap 应用程序图形仅在 iOS 上损坏?

为啥外部链接在构建后在 phonegap 应用程序上不起作用

为啥我的 phongap 应用程序在 android 状态栏中显示一个汉堡包图标?