I have a problem that I've been stuck for 2 weeks trying to understand and solve. In the application I have a RecycleView
, so I also have a system that reads and adds a listener(stream) to a Cloud Firestore document, when data changes in the database it is automatically placed in a DictProperty
. But the real problem is in RecycleView
, when database data is changed, RecycleView is affected for some reason and an error is returned:
Traceback (most recent call last):
File "jnius/jnius_proxy.pxi", line 156, in jnius.jnius.invoke0
File "jnius/jnius_proxy.pxi", line 124, in jnius.jnius.py_invoke0
AttributeError: 'list' object has no attribute 'invoke'
List refers to RecycleView's data attribute
E Ã s vezes retornava esse outro error:
Traceback (most recent call last):
File "jnius/jnius_proxy.pxi", line 156, in jnius.jnius.invoke0
File "jnius/jnius_proxy.pxi", line 124, in jnius.jnius.py_invoke0
AttributeError: 'kivy.properties.PropertyStorage' object has no attribute 'invoke'
I have no idea how to solve this, and the reason for this error. Please if anyone can help me. I'm using the cloud firestore API.
Eu sei que a melhor solução é migrar para java, mas estou tentando me familiarizar com o android com python primeiro. Pretendo aprender java no futuro.
main.py
from kivy.properties import DictProperty, BooleanProperty
from kivy.uix.screenmanager import ScreenManager
from kivymd.app import MDApp
class WindowManager(ScreenManager):
pass
class MyApp(MDApp):
profile_data = DictProperty(rebind=True)
registered = BooleanProperty(False)
loaded_data = BooleanProperty(False)
def __init__(self, **kwargs):
super(MyApp, self).__init__(**kwargs)
self.sm = WindowManager()
def build(self):
return self.sm
def on_start(self):
import android_db
self.bind(profile_data=self.check_profile_data)
android_db.read_firebase_data("collection", "person")
return super().on_start()
def check_profile_data(self, *args):
if self.profile_data == {}:
self.registered = False
elif len(self.profile_data) >= 7:
self.registered = True
if __name__ == "__main__":
MyApp().run()
To do the java part I followed this tutorial: https://www.youtube.com/watch?v=aZGXJXzGLhI&t=20s
android_db.py
from jnius import autoclass, cast, PythonJavaClass, java_method
from kivy.app import App
PythonActivity = autoclass("org.kivy.android.PythonActivity")
currentActivity = cast("android.app.Activity", PythonActivity.mActivity)
context = cast("android.content.Context", currentActivity.getApplicationContext())
FirebaseApp = autoclass("com.google.firebase.FirebaseApp")
FirebaseFirestore = autoclass("com.google.firebase.firestore.FirebaseFirestore")
FirebaseApp.initializeApp(context)
db = FirebaseFirestore.getInstance()
APP_INSTANCE = App.get_running_app()
def read_firebase_data(collection:str, document:str):
ref = db.collection(collection).document(document).get()
ref.addOnSuccessListener(DataSuccessListener())
listener = None
def stream_firebase_data(collection:str, document:str):
global listener
ref = db.collection(collection).document(document)
if listener is None:
listener = ref.addSnapshotListener(DataSnapshotListener())
class DataSuccessListener(PythonJavaClass):
__javainterfaces__ = ["com/google/android/gms/tasks/OnSuccessListener"]
__javacontext__ = "app"
@java_method("(Ljava/lang/Object;)V")
def onSuccess(self, doc):
data = doc.getData()
for key in data.keySet():
APP_INSTANCE.profile_data[key] = data.get(key)
print(APP_INSTANCE.profile_data)
stream_firebase_data("collection", doc.id)
class DataSnapshotListener(PythonJavaClass):
__javainterfaces__ = ["com/google/firebase/firestore/EventListener"]
__javacontext__ = "app"
@java_method('(Ljava/lang/Object;Lcom/google/firebase/firestore/FirebaseFirestoreException;)V')
def onEvent(self, doc, error):
try:
data = doc.getData()
for key in data.keySet():
APP_INSTANCE.profile_data[key] = data.get(key)
print(APP_INSTANCE.profile_data)
APP_INSTANCE.loaded_data = True
except Exception as e:print(e)
RecycleView.py
from kivy.uix.recycleview import RecycleView
class MyRecycleView(RecycleView):
pass
RecycleView.kv
<MyRecycleView>:
viewclass: "MD2Card"
effect_cls: "ScrollEffect"
RecycleBoxLayout:
default_size: None, None
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
spacing: dp(25)
padding: [0, dp(5), 0, dp(10)]
Location I'm using MyRecycleView
Screen:
name: "peq"
MyRecycleView:
id: small
Screen:
name: "med"
MyRecycleView:
id: mid
Screen:
name: "gra"
MyRecycleView:
id: big
In main.py
there is load_data
, it is used for when the Cloud Firestore data is loaded and added to the profile_data
, load the data attribute of the RecycleView
When the screen containing the RecyclerView
is loaded which is before the read_firebase_data
function in the main.py
file in on_start
, this function is done:
def update(self, **kwargs):
self.app = App.get_running_app()
self.app.bind(loaded_data=self.testt)
@mainthread
def testt(self, *ars):
if self.app.loaded_data:
self.ids.small.data = [
{
"size_hint":(.75, None),
"pos_hint":{"center_x":.5},
"md_bg_color":get_color_from_hex("#8758b3")
} for _ in range(20)
]
This function works great, the data is put in the RecycleView
, but when the data is changed an error is returned:
AttributeError: 'list' object has no attribute 'invoke'
Please if anyone can help me I will be very grateful, and I'm sorry if my explanation was not very good. Thank you in advance for your attention.
source https://stackoverflow.com/questions/73178696/cloud-firestore-api-issue-with-listeners-python-kivy-jnius-jnius-proxy-pxi-erro
Comments
Post a Comment