Как предотвратить утечки памяти при закрытии экземпляра Kivy ModalView? - PullRequest
0 голосов
/ 18 апреля 2019

В моем приложении я создаю экземпляры ModalView, которые содержат дочерние виджеты с обратными вызовами, которые привязаны к свойствам виджетов или запланированы с помощью Clock. Вот пример кода, чтобы продемонстрировать это. Я обнаружил, что метод dismiss() экземпляра ModalView оставляет нетронутыми привязки обратного вызова и запланированные обратные вызовы Clock его дочерних виджетов. Я должен позаботиться о том, чтобы освободить и распланировать их сам. Это может запутаться, когда я связываюсь с обратными вызовами, которые принимают аргументы (тогда я должен использовать методы fbind и funbind_uid, сохраняя при этом uid s). Точно так же запланированные обратные вызовы Clock, которые принимают аргументы, являются непростыми для планирования, так как тогда они являются анонимными, будучи запланированными с использованием лямбда-выражения или частичного.

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 dismiss() оставляет другие объекты, о которых я даже не подозреваю? Какой хороший способ обнаружить такие объекты, оставленные позади? Есть ли способ обеспечить полное уничтожение дочерних виджетов экземпляра ModalView при dismiss()?

1 Ответ

0 голосов
/ 18 апреля 2019

Я думаю, вы все делаете правильно.Когда ModalView равен dismissed, его ссылка в родительском окне удаляется, и если никакие другие ссылки на него нигде не хранятся, он будет собирать мусор, а любые содержащиеся в нем ссылки также будут собираться мусором.Тем не менее, Clock.schedule_interval() содержит ссылку на ModalView, поэтому он не собирает мусор.Это правильное поведение, поскольку ваш вызов для планирования событий означает, что вы хотите, чтобы эти запланированные события продолжались до тех пор, пока они не будут отменены.

Более простой способ отменить запланированные события - использовать:

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

в методе __init__() из MyWidget.Затем в методе cleanup() используйте:

self.sched.cancel()

Вам не нужно отвязывать привязку timenow, так как она исчезнет с сборкой мусора, которая произойдет после cancel.

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