【问题标题】:Confirmation of Best Practice: Removing EventListeners确认最佳实践:删除事件侦听器
【发布时间】:2016-02-12 13:57:46
【问题描述】:

我想了解删除附加了事件侦听器的项目时的最佳做法。

例如:

我有一个包含许多子项的滚动视图。我想用不同的项目列表刷新滚动视图的内容。

滚动视图中包含的每个项目都附加了一个或多个事件监听器。

我应该在删除项目之前删除事件侦听器吗? 或者 删除项目是否会自动清除任何附加的事件侦听器?

我试图通过让不再存在的 UI 对象的活动侦听器来确保不会影响性能或内存消耗。

【问题讨论】:

    标签: memory-management appcelerator event-listener appcelerator-titanium


    【解决方案1】:

    您应该阅读this

    JavaScript 解释器扫描内存,寻找没有引用的对象。然后将它们销毁以释放它们正在消耗的内存。

    如果一个对象从内存中删除,它的事件监听器也会消失。您无需再次调用 removeEventListener()。

    因此,在您的情况下,删除子视图并确保没有其他对它的引用就足够了。

    【讨论】:

      【解决方案2】:

      好问题。内存在移动设备上是“宝贵的”(以最好的咕噜口音完成),制造泄漏肯定会导致崩溃、低星级和不满意的用户。关于在添加/删除视图和关闭窗口时如何处理垃圾收集存在一些误解。关闭窗口清理子视图,使用.remove()方法实际上是从内存中删除视图等

      在这个特定的用例中,由于没有代码示例,我将不得不推测您如何创建子视图以及如何处理和设置事件侦听器,但通常这应该适用于大多数事情。

      对于您的视图,我们假设您已在 Alloy 视图文件中定义了一个 ScrollView (id='scrollView'),并且您创建子视图的操作如下:

      var subViews = [];
      
      function _doSomething(){
          alert('Something!');
      }
      
      for(i=0;i<10;i++){
          var view = Ti.UI.createView({
              backgroundColor:"#ececec", 
              height:50, 
              width: Ti.UI.FILL});
      
          view.addEventListener('click', _doSomething);
      
          subViews.push(view);
          $.scrollView.add(view);
      }
      

      在上面的例子中,我们做了几件事:

      1) 我们创建一个数组来保存我们所有的子视图,所以如果我们需要引用一个特定的视图(咳咳,垃圾回收)我们可以

      2) 我们声明了我们的事件函数,而不是在事件监听器中创建它,所以我们可以在需要时清理它

      那么现在 - 在任何用例中,我们都准备好管理这个特定视图的内存。

      现在假设您决定删除该特定 ScrollView 的所有视图,并使用如下内容:

      $.scrollView.removeAllChildren();
      

      然后开始添加您的新视图。您的子视图刚刚消失了吗?事件监听器呢?

      答案 - 他们仍然在附近徘徊。它很容易检查,只需抛出

      console.log(subViews.length);
      

      在您用于添加视图的代码末尾(如上面的示例),您会看到类似这样的内容。

      [INFO]  10
      [INFO]  20
      [INFO]  30
      [INFO]  40
      [INFO]  50
      [INFO]  60
      [INFO]  70
      

      因此,有了这些信息,您现在应该对在准备好清除子视图时如何清理它们有了一个很好的了解。下面是一个例子:

      function cleanUpSubViews(){
          while(subViews.length) {
              var v = subViews.pop();
              v.removeEventListener('click', _doSomething);
              v = null;
          };
      }
      

      一般来说,清理子视图应该清除事件监听器,但是为了确保我会建议在上面的代码中添加一行来确定处理它。

      您可以在此处查看一个工作示例: https://gist.github.com/grantges/884ae6b2fd8570a89109

      请务必查看我们在 Managing MemoryBest Practice Guides 上的文档,以获取更多信息和清晰度。

      【讨论】:

      • 伯特,感谢您的详细回复。问题的主要原因是这是一个跨平台解决方案(iOS、Android 和 MobileWeb),目前 MobileWeb 不支持 removeAllChildren。因此,我们希望手动删除项目。在可能的情况下,我们将删除容器滚动视图并重建它,而不是遍历子项并删除它们。我试图确定的是(在删除父滚动视图时)我是否可以避免删除所有子项,并且因为他们有事件侦听器也会删除所有子项。
      • 详细阅读了您的回复。我可以看到手动删除父滚动视图是不够的。因此,我正在修改我的代码,以确保删除所有子视图(及其事件侦听器)。
      • 如果没有其他对父子视图的引用,删除父滚动视图就足够了。在 Bert 的示例中,子视图存储在数组中。这就是为什么您必须将它们从数组中删除(仅使用subViews = null)。此外,不需要v.removeEventListenerv = null。在下面检查我的答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-05-05
      • 2014-11-24
      • 2014-10-13
      • 1970-01-01
      • 2018-09-04
      • 2022-08-03
      • 1970-01-01
      相关资源
      最近更新 更多