Почему происходит сбой приложения Android PhoneGap при вставке данных в SQL? - PullRequest
3 голосов
/ 09 июня 2011

У меня работает приложение PhoneGap в Android. Когда приложение запускается, оно вставляет примерно 500 строк в SQL. Таблица имеет 10 столбцов. Это не много данных, у меня есть JSON в текстовом файле, и его размер составляет около 120 кБ. Я думал, что это не может касаться каких-либо ограничений, но, возможно, есть некоторые ограничения, о которых я не знаю, или, возможно, ошибка в Android, потому что это же приложение работает на некоторых версиях Android (2.2) без проблем, но сразу вылетает или через несколько минут при работе с базой данных SQL на других версиях Android (1.6, 2.1, некоторые 2.3, вероятно, больше ...)

Вот код, который я использую для заполнения БД, которая падает на 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?

EDIT:

Вот вывод 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)

Ответы [ 3 ]

4 голосов
/ 28 марта 2012

Ответ Фобоса содержит некоторую относящуюся к делу информацию, но он не включает, как он относится к вашей проблеме или как решить вашу конкретную проблему. Я столкнулся с подобной проблемой, когда проводил некоторое тестирование производительности в javascript для Android, который обращается к java через объект, связанный с контекстом webview с помощью addJavascriptInterface. Хотя я явно не использую JNI, очевидно, что под прикрытием связанный интерфейс использует JNI для маршалинга данных - я получил ошибку и трассировку стека, аналогичную вашей. По-видимому, webDB или localStorage или все, что вы там делаете, также использует JNI под прикрытием.

Согласно информации, которую связал Фобос, существует ограниченное количество ссылок, которые вы можете иметь в области действия при использовании JNI. В случае javascript, который косвенно использует JNI, кажется, что ссылки должны храниться в зависимости от области видимости javascript. Глядя на ваш код, я не уверен, что именно вы делаете, чтобы превысить лимит, но похоже, что это может быть либо количество вызовов, которые вы делаете в транзакции в целом, либо ваши массивы значений в конечном итоге содержат более 512 элементов. Если вам нужно сохранить целостность транзакций и у вас действительно более 500 операций, вам может не повезти. Однако я подозреваю, что вы сможете найти способ обойти ограничение в 512, переписав свой код для создания строки запроса вне области вызова tx.executeSql.

Может быть, вы могли бы переписать код для построения строк запроса, а затем фактически вызвать tx.executeSql в оболочке анонимной функции? Возможно, вам нужно создавать строки, содержащие значения, а не использовать синтаксис 'INSERT INTO table() VALUES()',[] ... Как я уже говорил выше, если у вас более 500 операций в транзакции, вы все равно можете столкнуться с проблемами, но это стоит попробовать !

P.S. Для справки, вот версия моего кода, которая вылетала вместе с исправлением:

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 голосов
/ 06 октября 2012

Может быть, вам нужна функция рекурсивного обратного вызова, подобная этой:

//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();
1 голос
/ 10 июня 2011

OK. Нашел ответ. Это ограничение в 512 местных ссылок. Что вам нужно сделать, это преобразовать их в глобальные ссылки с помощью NewGlobalRef (), или в ближайшее время очистить местных жителей после создания их, если они не нужны. Однако изменение их на глобальные ссылки приведет к утечке памяти.

Проверьте эту ветку для получения дополнительной информации об этой известной проблеме.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...