webview 问题和 Ti.App.addEventListener 导致崩溃

issue with webview and Ti.App.addEventListener causing crash

请原谅丑陋的代码,这是我可以用来重现错误的实际代码的最简单版本。我基本上使用钛中的 WebView 打开本地保存的 .htm 文件,以便我可以利用 HTML5 图形功能。我在做什么工作正常。问题是我需要将一些数据传递到 htm 文件,我正在按照文档推荐的方式进行操作 - 使用 Ti.App.fireEvent - 这有效......一次。但是,如果我离开 window 然后再次导航回来,它会失败并给我一个 NS_ERROR_NOT_AVAILABLE。我已经在 firefox 中将此代码作为 Web 预览进行了尝试,并在 Android 设备和模拟器上进行了尝试,每个设备和模拟器都存在相同的问题。很明显,如果回调视图,它不会以相同的方式加载,我猜它是从堆栈中拉回的,这与 'load' 事件侦听器或其他东西混淆,但我不知道如何要解决这个问题。这是我的代码的简化版本,只是为了演示这个问题:

app.js

Titanium.UI.setBackgroundColor('#000');

var win = Ti.UI.createWindow({
    layout: 'vertical',
});

var wv = Ti.UI.createWebView({
    url: 'test.htm',
    height: '50%'
});

var but = Ti.UI.createButton({
    width: 100,
    height: 50,
    title: 'Press',
});

var wvopen = false;

but.addEventListener('click', function() {
    if (wvopen === false) {
        win.add(wv);
        wvopen = true;
    } else {
        win.remove(wv);
        wvopen = false;
    }

});

wv.addEventListener('load', function() {
   Ti.App.fireEvent('go'); 
});

win.add(but);
win.open();

以及 .htm 文件:

test.htm

<!doctype html>
<html>
<head>
    <title>Test</title>
</head>
<body>
    <p>A Little Test</p>
    <script>
        var Ti = window.parent.Ti;
        Ti.App.addEventListener('go', function(){
            alert(1);
        });
    </script>
</body>
</html>

试试这个,

but.addEventListener('click', function() {
   if (wvopen === false) {
      win.add(wv);
      wvopen = true;
   } else {
      win.remove(wv);
      wv.release();
      wvopen = false;
   }
});

最终我自己找到了答案。它在文档中,但意识到问题到底是什么以及为什么会发生并不总是那么简单,所以我觉得值得我自己在这里回答以供其他人使用。

重点是:

"Keep in mind that app-level events are global, which means they remain in context the entire time your app is running (unless you remove them). This also means that any objects they reference will also remain in scope while your app runs. This could prevent those objects from being garbage collected. See the Managing Memory and Finding Leaks chapter for more information."

~ Titanium 文档。

link: https://wiki.appcelerator.org/display/guides2/Event+Handling#EventHandling-Application-LevelEvents

所以基本上事件侦听器将存在,即使它没有加载并且您尝试删除它存在的上下文。因此,您必须同时删除事件侦听器并使持有它的视图无效。

在实践中,具体实施可能会有所不同,具体取决于您的具体情况,但这是我想出的。

注意...可能有更有效的方法来执行此操作,在这种情况下请告诉我。

app.js

 /*
 * Build window and buttons
 */

var win = Ti.UI.createWindow({
    layout: 'vertical',
    backgroundColor:'black'
});


var but = Ti.UI.createButton({
    top: 20,
    width: 200,
    height: 50,
    title: 'Toggle WV',
});

var but2 = Ti.UI.createButton({
    top: 20,
    width: 200,
    height: 50,
    title: 'Fire Event'
});

var wv;
function newWv(){
    wv = Ti.UI.createWebView({
        top:20,
        right: 20,
        left: 20,
        height: '50%',
        url: 'test.htm',
    });
}

win.add(but);
win.add(but2);

/*
 * Main functionality goes here of tests goes here.
 */
var isVisible = false;


but.addEventListener('click', function() {
    if (isVisible) {
        win.remove(wv);
        Ti.App.fireEvent('close');
        wv = null;
        isVisible = false;
    } else {
        newWv();
        win.add(wv);
        isVisible = true;
    }    
});

but2.addEventListener('click', function() {
    try{
        Ti.App.fireEvent('go'); 
    } catch(e) {
        alert(e);
    }
});

win.open({modal:true});

然后在 htm 文件中做一些修改:

test.htm

<!doctype html>
<html>
<head>
    <title>Test</title>
</head>
<body>
    <p>A Little Test</p>
    <script>
        var Ti = window.parent.Ti;
        var go = function() {
            alert('called by Titanium app');
        };
        var close = function() {
            Ti.App.removeEventListener('go',go);
            Ti.App.removeEventListener('close',close);
        };
        window.addEventListener('load', function() {
            Ti.App.addEventListener('go', go);
            Ti.App.addEventListener('close', close);
        }); 

    </script>
</body>
</html>