解除Kivy ModalView实例时如何防止内存泄漏?

时间:2019-04-18 11:24:35

标签: python kivy

在我的应用程序中,我创建ModalView实例,该实例包含子小部件以及绑定到小部件属性或由Clock调度的回调。这是一个示例代码来演示这一点。我发现ModalView实例的dismiss()方法保留了其子窗口小部件的回调绑定和Clock计划的回调。我必须自己解决这些问题并使其不受约束。当我绑定到使用args的回调时,这可能会变得混乱(然后,我必须使用fbindfunbind_uid方法,同时要跟踪uid s)。同样,采用args的Clock计划的回调很难进行计划,因为那时它们是匿名的(使用lambda或部分计划)。

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
from kivy.uix.modalview import ModalView
from kivy.uix.label import Label
from kivy.lang import Builder
from kivy.properties import StringProperty
from kivy.properties import ObjectProperty
from kivy.clock import Clock
import datetime


Builder.load_string('''
#: kivy 1.9.2

<MainWidget>:
    Button:
        text: 'Push the button (pu-push the button)'
        on_press:
            root.showtime()
''')



class MyWidget(FloatLayout):
    text=StringProperty() # this can be bound to 'text' property of a child widget for observation
    timenow=ObjectProperty()


    def __init__(self, **kwargs):
        super(FloatLayout, self).__init__(**kwargs)
        self.bind(timenow=self.update_text)
        Clock.schedule_interval(self.poll_datetime, .5)


    def poll_datetime(self, dt):
        self.timenow = datetime.datetime.now()
        print "polling datetime"


    def update_text(self, *args):
        self.text=self.timenow.strftime("%Y-%m-%d %H:%M:%S")
        print "updating text"


    def cleanup(self, *args):
        self.unbind(timenow=self.update_text)
        Clock.unschedule(self.poll_datetime)
        print "cleaning up"


class MainWidget(FloatLayout):

    def __init__(self, **kwargs):
        super(MainWidget, self).__init__(**kwargs)

    def showtime(self):

        overlay = ModalView()
        container=MyWidget()
        timelabel=Label()
        container.bind(text=timelabel.setter('text'))
        container.bind(pos=timelabel.setter('pos'))
        container.add_widget(timelabel)
        cancelbutton=Button(text='Cancel', size_hint=(None, None))
        cancelbutton.bind(on_press=container.cleanup)     
        cancelbutton.bind(on_press=overlay.dismiss) 
        container.add_widget(cancelbutton)
        overlay.add_widget(container)  
        overlay.open()


class MyApp(App):
    def build(self):
        mw=MainWidget()
        return mw


if __name__ == '__main__':
    MyApp().run()

我这样做正确吗? ModalView的{​​{1}}方法是否会将我什至不知道的其他对象抛在后面?检测此类残留物的好方法是什么?有没有一种方法可以确保在调用dismiss()时完全销毁ModalView实例的子窗口小部件?

1 个答案:

答案 0 :(得分:0)

我认为您做对了。当ModalViewdismissed时,其在父窗口中的引用将被删除,并且如果没有任何其他引用保留在任何地方,则将对其进行垃圾回收,并且其持有的所有引用也将为垃圾。集。但是,Clock.schedule_interval()持有对ModalView的引用,因此不会收集垃圾。这是正确的行为,因为对计划事件的调用意味着您希望这些计划的事件继续下去直到被取消。

取消预定事件的更简单方法是使用:

self.sched = Clock.schedule_interval(self.poll_datetime, .5)

__init__()的{​​{1}}方法中。然后在MyWidget方法中使用:

cleanup()

您无需取消绑定self.sched.cancel() 的绑定,因为绑定将消失,而垃圾回收将在timenow之后发生。