Skip to main content
 首页 » 编程设计

android之Kivy 小部件创建真的这么慢还是我做错了

2025年01月19日37davidwang456

我注意到我的应用程序中的小部件创建速度很慢,因此我创建了这个简单的测试应用程序来检查它。它包含两个屏幕,每个屏幕都包含简单的小部件列表。

应用:

from kivy.app import App 
from kivy.uix.screenmanager import ScreenManager, Screen 
from kivy.uix.boxlayout import BoxLayout 
from kivy.properties import ObjectProperty, StringProperty 
from kivy.clock import Clock 
 
from time import time 
 
class ListScreen(Screen): 
 
    items_box = ObjectProperty(None) 
 
    def on_enter(self): 
        start = time() 
        for i in range(0,50): 
            self.items_box.add_widget(ListItem('Item '+str(i))) 
        self.items_box.bind(minimum_height=self.items_box.setter('height')) 
        print time()-start 
 
    def on_leave(self): 
        self.items_box.clear_widgets() 
 
class ListItem(BoxLayout): 
 
    title = StringProperty('') 
 
    def __init__(self, title, **kwargs): 
        super(ListItem, self).__init__(**kwargs) 
        self.title = title 
 
class ListApp(App): 
 
    sm = ScreenManager() 
    screens = {} 
 
    def build(self): 
        self.__create_screens() 
        ListApp.sm.add_widget(ListApp.screens['list1']) 
        Clock.schedule_interval(self._switch, 1) 
        return ListApp.sm 
 
    def _switch(self, *args): 
        ListApp.sm.switch_to(ListApp.screens['list1' if ListApp.sm.current != 'list1' else 'list2']) 
 
    def __create_screens(self): 
        ListApp.screens['list1'] = ListScreen(name='list1') 
        ListApp.screens['list2'] = ListScreen(name='list2') 
 
if __name__ == '__main__': 
    ListApp().run() 

list.kv 文件:

<ListScreen>: 
    items_box: items_box 
    BoxLayout: 
        orientation: "vertical" 
        AnchorLayout: 
            size_hint_y: 0.1 
            padding: self.width*0.1, self.height*0.05 
            Label: 
                font_size: root.height*0.05 
                text: "Some list" 
        ScrollView: 
            size_hint_y: 0.9 
            size: self.size 
            BoxLayout: 
                id: items_box 
                orientation: "vertical" 
                padding: self.width*0.1, 0 
                size_hint_y: None 
 
<ListItem>: 
    orientation: "horizontal" 
    size_hint_y: None 
    height: app.sm.height*0.1 
    Label: 
        font_size: app.sm.height*0.025 
        text: root.title 
        size_hint_x: 0.9 
        text_size: self.size 
        valign: "middle" 
    CheckBox 
        size_hint_x: 0.1 

登录我的设备(Moto G):

11-28 11:44:09.525  1848  2044 I python  : 0.5793800354 
11-28 11:44:10.853  1848  2044 I python  : 0.453143119812 
11-28 11:44:12.544  1848  2044 I python  : 0.633069992065 
11-28 11:44:13.697  1848  2044 I python  : 0.369570970535 
11-28 11:44:14.988  1848  2044 I python  : 0.594089031219 
11-28 11:44:16.017  1848  2044 I python  : 0.339677095413 
11-28 11:44:17.315  1848  2044 I python  : 0.58710193634 
11-28 11:44:18.403  1848  2044 I python  : 0.359042882919 
11-28 11:44:19.741  1848  2044 I python  : 0.613200187683 
11-28 11:44:20.820  1848  2044 I python  : 0.359098911285 
11-28 11:44:22.139  1848  2044 I python  : 0.60958814621 
11-28 11:44:23.199  1848  2044 I python  : 0.354372024536 
11-28 11:44:24.538  1848  2044 I python  : 0.643312931061 
11-28 11:44:25.606  1848  2044 I python  : 0.360656023026 
11-28 11:44:26.995  1848  2044 I python  : 0.682018995285 
11-28 11:44:28.140  1848  2044 I python  : 0.393831014633 
11-28 11:44:29.470  1848  2044 I python  : 0.591700077057 
11-28 11:44:30.525  1848  2044 I python  : 0.346837043762 
11-28 11:44:31.818  1848  2044 I python  : 0.607005834579 
11-28 11:44:32.877  1848  2044 I python  : 0.36404299736 
11-28 11:44:34.149  1848  2044 I python  : 0.586351156235 
11-28 11:44:35.195  1848  2044 I python  : 0.349910974503 
11-28 11:44:36.484  1848  2044 I python  : 0.588956832886 
11-28 11:44:37.547  1848  2044 I python  : 0.367785930634 
11-28 11:44:38.886  1848  2044 I python  : 0.639610052109 
11-28 11:44:40.007  1848  2044 I python  : 0.394254922867 
11-28 11:44:41.464  1848  2044 I python  : 0.732916116714 

来吧,真的吗?创建带有标签和复选框的 50 行的简单列表平均需要 0.5 秒?还是我做错了什么?

请您参考如下方法:

感谢 Alexander Taylor(Kivy 开发人员之一)找到了解决方案。这是他的回答:

Widget creation is relatively slow, especially depending on what the widget contains.

If making big lists, like in your examples, you're usually better off using RecycleView. This optimises things to reuse a smaller number of widgets during the scrolling.

所以我试过了。

应用:

from kivy.app import App 
from kivy.uix.screenmanager import ScreenManager, Screen 
from kivy.properties import ObjectProperty 
from kivy.clock import Clock 
 
from time import time 
 
class ListScreen(Screen): 
 
    recycle_view = ObjectProperty(None) 
    items_box = ObjectProperty(None) 
 
    def on_enter(self): 
        start = time() 
        for i in range(0,50): 
            self.recycle_view.data.append({'title': 'item'+str(i)}) 
        print time()-start 
 
    def on_leave(self): 
        self.recycle_view.data = [] 
 
class ListApp(App): 
 
    sm = ScreenManager() 
    screens = {} 
 
    def build(self): 
        self.__create_screens() 
        ListApp.sm.add_widget(ListApp.screens['list1']) 
        Clock.schedule_interval(self._switch, 1) 
        return ListApp.sm 
 
    def _switch(self, *args): 
        ListApp.sm.switch_to(ListApp.screens['list1' if ListApp.sm.current != 'list1' else 'list2']) 
 
    def __create_screens(self): 
        ListApp.screens['list1'] = ListScreen(name='list1') 
        ListApp.screens['list2'] = ListScreen(name='list2') 
 
if __name__ == '__main__': 
    ListApp().run() 

list.kv 文件:

<ListScreen>: 
    recycle_view: recycle_view 
    items_box: items_box 
    BoxLayout: 
        orientation: "vertical" 
        AnchorLayout: 
            size_hint_y: 0.1 
            padding: self.width*0.1, self.height*0.05 
            Label: 
                font_size: root.height*0.05 
                text: "Some list" 
        RecycleView: 
            id: recycle_view 
            size_hint: 1, 0.9 
            viewclass: "ListItem" 
            RecycleBoxLayout: 
                id: items_box 
                orientation: "vertical" 
                padding: self.width*0.1, 0 
                default_size_hint: 1, None 
                size_hint: 1, None 
                height: self.minimum_height 
 
<ListItem@BoxLayout>: 
    orientation: "horizontal" 
    size_hint: 1, None 
    height: app.sm.height*0.1 
    title: '' 
    Label: 
        font_size: app.sm.height*0.025 
        text: root.title 
        size_hint_x: 0.9 
        text_size: self.size 
        valign: "middle" 
    CheckBox 
        size_hint_x: 0.1 

登录同一设备(Moto G):

11-29 13:11:58.196 13121 13203 I python  : 0.00388479232788 
11-29 13:11:59.192 13121 13203 I python  : 0.00648307800293 
11-29 13:12:00.189 13121 13203 I python  : 0.00288391113281 
11-29 13:12:01.189 13121 13203 I python  : 0.00324606895447 
11-29 13:12:02.194 13121 13203 I python  : 0.00873804092407 
11-29 13:12:03.188 13121 13203 I python  : 0.00265002250671 
11-29 13:12:04.209 13121 13203 I python  : 0.00614500045776 

快了 100 多倍!太棒了。