Reputation: 472
I've noticed that the widgets creation in my app is slow so I've created this simple test app to check it. It contains two screens and each of them contains simple list of widgets.
App:
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 file:
<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
Log on my device (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
Come on, really? Simple list of 50 rows with label and checkbox needs 0.5 seconds on average to be created? Or am I doing something wrong?
Upvotes: 6
Views: 3350
Reputation: 472
The solution was found thanks to Alexander Taylor (one of Kivy developers). Here is his answer:
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.
So I've tried.
App:
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 file:
<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
Log on the same device (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
More than 100 times faster! It's awesome.
Upvotes: 3