【问题标题】:How to abort loading component in Loader?如何在 Loader 中中止加载组件?
【发布时间】:2017-04-12 13:36:19
【问题描述】:

我有一个Loader 对象,它加载了一些非常重的组件。某些事件在加载过程中到达,需要停止加载并返回以清空Loader。有可能吗?

【问题讨论】:

  • 应该使用asyncronous Loader。但是这个属性让我失望了。虽然UI 没有像承诺的那样冻结(BusyIndicator 正在运行),但它仍然完全没有响应。
  • 我设置了asynchronous,但问题是它会在加载器中的对象未完成加载时破坏它们,从而导致警告和错误。
  • active设置为false或将source/sourceComponent设置为null怎么样?
  • 我不知道之前出了什么问题,但是再次写它,它可以工作......
  • @folibis 然后它似乎永远不会删除任何对象并最终耗尽内存。

标签: c++ qt qml loader qqmlcomponent


【解决方案1】:

中止对象创建

如 Qt 所述,存在三种方法来卸载/中止对象实例化:

  1. Loader.active 设置为false
  2. Loader.source 设置为空字符串
  3. Loader.sourceComponent 设置为undefined

异步行为

为了能够在加载期间更改这些属性,Loader.asynchronous 应该是 true,否则 GUI 线程正忙于加载对象。您还需要QQmlIncubationController 为您的QQmlEngine 控制用于对象孵化的空闲时间。没有这样的控制器Loader.asynchronous 没有任何效果。请注意,如果场景包含QQuickWindowQQmlApplicationEngine 会自动安装默认控制器。

错误

直到最后测试的 Qt 版本(Qt 5.8.0、5.9.0 beta),在中止未完成的对象孵化时存在严重的内存泄漏(至少在某些情况下,包括 derM 答案中的示例)导致大型组件的内存使用量快速增加。将创建一个 bug report,其中包含建议的解决方案。

【讨论】:

    【解决方案2】:

    我不知道您的问题是什么,那些 在加载程序完成之前被销毁的对象,但问题可能存在吗?如果没有,这应该工作: 如果它没有帮助,请在您的问题中添加一些代码,以重现您的问题。

    ma​​in.qml

    import QtQuick 2.7
    import QtQuick.Controls 2.0
    
    ApplicationWindow {
        id: root
        visible: true
        width: 400; height: 450
    
        Button {
            text: (complexLoader.active ? 'Loading' : 'Unloading')
            onClicked: complexLoader.active = !complexLoader.active
        }
    
        Loader {
            id: complexLoader
            y: 50
            width: 400
            height: 400
            source: 'ComplexComponent.qml'
            asynchronous: true
            active: false
            // visible: status === 1
        }
    
        BusyIndicator {
            anchors.fill: complexLoader
            running: complexLoader.status === 2
            visible: running
        }
    }
    

    ComplexComponent.qml

    import QtQuick 2.0
    
    Rectangle {
        id: root
        width: 400
        height: 400
        Grid {
            id: grid
            anchors.fill: parent
            rows: 50
            columns: 50
            Repeater {
                model: parent.rows * parent.columns
                delegate: Rectangle {
                    width: root.width / grid.columns
                    height: root.height / grid.rows
                    color: Qt.rgba(Math.random(index),
                                   Math.random(index),
                                   Math.random(index),
                                   Math.random(index))
                }
            }
        }
    }
    

    【讨论】:

    • 如果你一直快速点击按钮,它永远不会释放为之前的对象分配的内存并最终导致 bad_alloc。
    • 您多久点击一次我的ComplexComponent? :D 我选择了一个计时器clicking 每 200 或 500 毫秒,并且这样做了几分钟。但是,是的,内存会随着时间的推移而增加......
    • 我将计时器设置为200,但将行数和列数增加到200。它的内存增长非常快并且崩溃了。
    • 对于 200x200,我没有看到任何内存增加(恒定 ~200MB)。对于较小的尺寸(50x50),我确实看到了增加,但这可以通过在卸载后手动调用gc(即垃圾收集)来避免。除了第一次,button.clicked() 需要很多时间(200x200 最多需要 6s),GUI 冻结,文件没有异步加载(Loader.Status 永远不会变成Loader.Loading)。在 Qt 5.8、Ubuntu 16.04 上测试。
    • 检查连续调用gc() 3-4次是否对内存使用有影响。一个很少够用,但 3-4 个似乎可以挤出尽可能多的垃圾。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-10-18
    • 2012-12-04
    • 2018-02-27
    • 1970-01-01
    • 2019-09-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多