0

I need to refresh recycle view when I recive data from stream. When I run below code I see

AttributeError: 'kivy.properties.DictProperty' object has no attribute 'requests_recycle_view'

It comes from methodrecycle_view_list I think there is some issue with instances but can't solve it. When I comment self.ids.requests_recycle_view.data = self.requests_tab and run refresh_recycle_view from button it works - I mean it refresh the list on the screen but I need it to run automatically when data in requests_tab changes from stream.

from kivy.config import Config
Config.set('graphics', 'multisamples', '0')
from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
import pyrebase
from kivy.properties import  ListProperty

config = {
    "apiKey": "String",
    "authDomain": "String",
    "databaseURL": "String",
    "projectId": "String",
    "storageBucket": "String",
    "messagingSenderId": "String"
  };

firebase = pyrebase.initialize_app(config)
db = firebase.database()

Builder.load_file('kv/main.kv')




#-------------------------------------------------------------ScreenManager

class ScreenManagement(ScreenManager):
    pass




#--------------------------------------------------------------RequestScreen

class RequestScreen(Screen):

    requests_tab =  ListProperty()

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

    def refresh_recycle_view(self):
        print('refresh',  self.requests_tab)
        self.ids.requests_recycle_view.data = self.requests_tab


    def recycle_view_list(self, listFromStream):
        print("recycle_view_list", listFromStream)

        self.requests_tab = listFromStream
        self.ids.requests_recycle_view.data = self.requests_tab

    @classmethod
    def setRequestTab(cls, tab):
        print("setRequestTab", tab)
        cls.recycle_view_list(RequestScreen ,tab)





# ------------------------------------------------------------stream_handler
def stream_handler(message):
    print(message["event"])  # put
    print(message["path"])  # /-K7yGTTEp7O549EzTYtI
    print(message["data"])  # {'title': 'Pyrebase', "body": "etc..."}

    pyreMessage = [{'text': message["data"]}]

    RequestScreen.setRequestTab(pyreMessage)



db.child("Requests").stream(stream_handler)




#---------------------------------------------------------------StreamApp
class StreamApp(App):
    def build(self):

        sm = ScreenManagement()
        sm.add_widget(RequestScreen(name="Bajot II"))
        return sm

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

main.kv

#main.kv
#:import FadeTransition kivy.uix.screenmanager.FadeTransition


<ScreenManagement>:
    transition: FadeTransition()
    RequestScreen:

<CustLabel@Label>
    halign: 'right'
    valign: 'middle'
    width: 80

<RequestScreen>
    name: "RequestScreen"

    requests_tab:   requests_recycle_view.data


    Button:
        size_hint_x: None
        width: 42
        text: "Done"
           on_press:   root.refresh_recycle_view()



    BoxLayout:
        #size_hint_y: None

        RecycleView:
            id: requests_recycle_view
            viewclass: 'CustLabel'
            data: root.requests_tab
            RecycleBoxLayout:
                spacing: 15
                default_size: 100, dp(25)
                default_size_hint: 1, None
                size_hint_y: None
                height: self.minimum_height
                orientation: 'vertical'
ikolim
  • 15,721
  • 2
  • 19
  • 29
ForyszeP
  • 143
  • 1
  • 15

1 Answers1

0

I have not been able to test this (I don't have your database), but I think it will work. I think your statement about instances is right. In the modified code below, I changed setRequestTab to an instance method:

from kivy.config import Config
Config.set('graphics', 'multisamples', '0')
from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
import pyrebase
from kivy.properties import  ListProperty

config = {
    "apiKey": "String",
    "authDomain": "String",
    "databaseURL": "String",
    "projectId": "String",
    "storageBucket": "String",
    "messagingSenderId": "String"
  };

firebase = pyrebase.initialize_app(config)
db = firebase.database()

Builder.load_file('kv/main.kv')




#-------------------------------------------------------------ScreenManager

class ScreenManagement(ScreenManager):
    pass




#--------------------------------------------------------------RequestScreen

class RequestScreen(Screen):

    requests_tab =  ListProperty()

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

    def refresh_recycle_view(self):
        print('refresh',  self.requests_tab)
        print(self.ids.requests_recycle_view)
        self.ids.requests_recycle_view.data = self.requests_tab


    def recycle_view_list(self, listFromStream):
        print("recycle_view_list", listFromStream)

        self.requests_tab = listFromStream
        self.ids.requests_recycle_view.data = self.requests_tab

    def setRequestTab(self, tab):
        print("setRequestTab", tab)
        self.recycle_view_list(tab)




# ------------------------------------------------------------stream_handler
def stream_handler(message):
    print(message["event"])  # put
    print(message["path"])  # /-K7yGTTEp7O549EzTYtI
    print(message["data"])  # {'title': 'Pyrebase', "body": "etc..."}

    pyreMessage = [{'text': message["data"]}]

    App.get_running_app().requestScreen.setRequestTab(pyreMessage)



db.child("Requests").stream(stream_handler)




#---------------------------------------------------------------StreamApp
class StreamApp(App):
    def build(self):

        sm = ScreenManagement()
        self.requestScreen = RequestScreen(name="Bajot II")
        sm.add_widget(self.requestScreen)
        return sm

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

I have saved a reference to the RequestScreen in the StreamApp, and then used that reference in the stream_handler(). That allows me to call setRequestTab() as an instance method. Again, this code is not tested, so there may be some errors.

John Anderson
  • 35,991
  • 4
  • 13
  • 36
  • Error: `App.get_running_app().requestScreen.setRequestTab(pyreMessage) AttributeError: 'StreamApp' object has no attribute 'requestScreen'`. If you can help I will create database for tests. – ForyszeP Feb 26 '19 at 15:16
  • Did you make the change in the `build()` method? (`self.requestScreen = RequestScreen(name="Bajot II")` and `sm.add_widget(self.requestScreen)`) – John Anderson Feb 26 '19 at 15:19
  • Yes I have. That's a bit odd for me now. – ForyszeP Feb 26 '19 at 15:31
  • Another possibility is that your `stream_handler` is getting called before the `StreamApp` is setup. If that is the case, then perhaps moving the `db.child("Requests").stream(stream_handler)` into a method of the `StreamApp` and calling that method via a `Clock.schedule_once()` in the `build()` method might fix it. You could also make `stream_handler` another method of the `StreamApp` and eliminate the need for the `App.get_running_app()` call. – John Anderson Feb 26 '19 at 15:35
  • Ok I will try. In the meantime I have set `Clock.schedule_interval` for `refresh_recycle_view`. I can see that clock works but the view does not refresh. I need to get a bit more knowledge about live cycle and how it accually works rather than just searching for ready solutions. Now it is a magic. Thanks for your help. I will come back later. – ForyszeP Feb 26 '19 at 17:32