java - विधि के परिणामस्वरूप DataSnapshot मान कैसे लौटाएं?




android firebase (3)

मुझे विश्वास है कि मैं समझता हूं कि आप क्या पूछ रहे हैं। यद्यपि आप कहते हैं कि आप इसे लाने के लिए चाहते हैं (यह प्रति) भ्रूण विधि से, यह कहने के लिए पर्याप्त हो सकता है कि आप वास्तव में अपने भ्रूण के पूरा होने के बाद प्राप्त मूल्य का उपयोग करने में सक्षम होना चाहते हैं। यदि हां, तो आपको यही करना होगा:

  1. अपनी कक्षा के शीर्ष पर एक चर बनाएं
  2. अपने मूल्य को पुनः प्राप्त करें (जो आपने ज्यादातर सही ढंग से किया है)
  3. सार्वजनिक वर्ग को प्राप्त मान के बराबर अपनी कक्षा में सेट करें

एक बार जब आपका भ्रूण सफल हो जाता है, तो आप चर के साथ कई काम कर सकते हैं। 4 ए और 4 बी कुछ सरल उदाहरण हैं:

4 ए। संपादित करें: उपयोग के एक उदाहरण के रूप में, आप अपनी कक्षा में जो कुछ भी चलाने की आवश्यकता है उसे ट्रिगर कर सकते हैं जो आपके yourNameVariable का उपयोग करता है (और आप यह सुनिश्चित कर सकते हैं कि यह yourNameVariable नहीं है)

4 बी। संपादित करें: उपयोग के एक उदाहरण के रूप में, आप एक बटन के onClickListener द्वारा ट्रिगर किए गए फ़ंक्शन में चर का उपयोग कर सकते हैं।

इसे इस्तेमाल करे।

// 1. Create a variable at the top of your class
private String yourNameVariable;

// 2. Retrieve your value (which you have done mostly correctly)
private void getUserName(String uid) {
    databaseReference.child(String.format("users/%s/name", uid))
            .addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            // 3. Set the public variable in your class equal to value retrieved
            yourNameVariable = dataSnapshot.getValue(String.class);
            // 4a. EDIT: now that your fetch succeeded, you can trigger whatever else you need to run in your class that uses `yourNameVariable`, and you can be sure `yourNameVariable` is not null.
            sayHiToMe();
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {}
    });
}

// (part of step 4a)
public void sayHiToMe() {
  Log.d(TAG, "hi there, " + yourNameVariable);
}

// 4b. use the variable in a function triggered by the onClickListener of a button.
public void helloButtonWasPressed() {
  if (yourNameVariable != null) {
    Log.d(TAG, "hi there, " + yourNameVariable);
  }
}

फिर, आप अपनी कक्षा में जहाँ भी चाहें, अपने yourNameVariable उपयोग कर सकते हैं।

नोट: बस यह सुनिश्चित करें कि आप जाँच करें कि yourNameVariable बाद से इसका उपयोग करते समय yourNameVariable शून्य नहीं है और अतुल्यकालिक है और जिस समय आप इसे कहीं और उपयोग करने का प्रयास करते हैं, तब तक पूरा नहीं हो सकता।

मुझे जावा के साथ बहुत अनुभव नहीं है। मुझे यकीन नहीं है कि यह सवाल बेवकूफ़ है, लेकिन मुझे फायरबेस रियलटाइम डेटाबेस से एक उपयोगकर्ता नाम प्राप्त करने की आवश्यकता है और इस विधि के परिणामस्वरूप यह नाम वापस करना होगा। इसलिए, मुझे पता चला कि यह मान कैसे प्राप्त किया जाए, लेकिन मुझे समझ नहीं आ रहा है कि इस पद्धति के परिणामस्वरूप इसे कैसे लौटाया जाए। ऐसा करने का सबसे अच्छा तरीका क्या है?

private String getUserName(String uid) {
    databaseReference.child(String.format("users/%s/name", uid))
            .addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            // How to return this value?
            dataSnapshot.getValue(String.class);
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {}
    });
}

यह एसिंक्रोनस वेब एपीआई के साथ एक क्लासिक मुद्दा है। आप अब कुछ वापस नहीं कर सकते हैं जो अभी तक लोड नहीं किया गया है। अन्य शब्दों के साथ, आप केवल एक वैश्विक चर नहीं बना सकते हैं और इसे onDataChange() विधि के बाहर उपयोग कर सकते हैं क्योंकि यह हमेशा null रहेगा। ऐसा इसलिए हो रहा है क्योंकि onDataChange() विधि को एसिंक्रोनस कहा जाता है। आपके कनेक्शन की गति और स्थिति के आधार पर, यह डेटा उपलब्ध होने से पहले कुछ सेकंड से कुछ सेकंड तक ले सकता है।

लेकिन न केवल फायरबेस रियलटाइम डेटाबेस डेटा को अतुल्यकालिक रूप से लोड करता है, लगभग सभी आधुनिक अन्य वेब एपीआई करते हैं, क्योंकि इसमें कुछ समय लग सकता है। इसलिए डेटा की प्रतीक्षा करने के बजाय (जो आपके उपयोगकर्ताओं के लिए अनुत्तरदायी एप्लिकेशन संवादों को जन्म दे सकता है), आपका मुख्य एप्लिकेशन कोड जारी रहता है, जबकि डेटा को द्वितीयक थ्रेड पर लोड किया जाता है। फिर जब डेटा उपलब्ध होता है, तो आपका onDataChange () विधि कहा जाता है और डेटा का उपयोग कर सकता है। दूसरे शब्दों के साथ, onDataChange() विधि को आपके डेटा को अभी तक लोड नहीं किया गया है कहा जाता है।

आइए एक उदाहरण लेते हैं, कोड में कुछ लॉग स्टेटमेंट डालकर और अधिक स्पष्ट रूप से देखने के लिए कि क्या चल रहा है।

private String getUserName(String uid) {
    Log.d("TAG", "Before attaching the listener!");
    databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            // How to return this value?
            dataSnapshot.getValue(String.class);
            Log.d("TAG", "Inside onDataChange() method!");
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {}
    });
    Log.d("TAG", "After attaching the listener!");
}

यदि हम इस कोड को चलाते हैं, तो आउटपुट wil होगा:

श्रोता को संलग्न करने से पहले!

श्रोता संलग्न करने के बाद!

OnDataChange () विधि के अंदर!

यह संभवतः वह नहीं है जिसकी आपने अपेक्षा की थी, लेकिन यह ठीक ही बताता है कि इसे वापस करते समय आपका डेटा क्यों null है।

अधिकांश डेवलपर्स के लिए प्रारंभिक प्रतिक्रिया इस asynchronous behavior कोशिश और "ठीक" asynchronous behavior , जिसे मैं व्यक्तिगत रूप से इसके खिलाफ asynchronous behavior हूं। वेब अतुल्यकालिक है, और जितनी जल्दी आप इसे स्वीकार करते हैं, उतनी ही जल्दी आप सीख सकते हैं कि आधुनिक वेब एपीआई के साथ उत्पादक कैसे बनें।

मैंने इस अतुल्यकालिक प्रतिमान के लिए समस्याओं को फिर से लिखना आसान पाया है। "पहले डेटा प्राप्त करें, फिर इसे लॉग इन करें" कहने के बजाय, मैं समस्या को "डेटा प्राप्त करना प्रारंभ करता हूं। जब डेटा लोड हो जाता है, तो इसे लॉग इन करें" के रूप में समस्या को फ्रेम करें। इसका मतलब है कि डेटा की आवश्यकता वाले किसी भी कोड को onDataChange() विधि के अंदर होना चाहिए या इस तरह से अंदर से बुलाया जाना चाहिए:

databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        // How to return this value?
        if(dataSnapshot != null) {
            System.out.println(dataSnapshot.getValue(String.class));
        }
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
});

यदि आप उस बाहर का उपयोग करना चाहते हैं, तो एक और तरीका है। आपको डेटा वापस करने के लिए Firebase की प्रतीक्षा करने के लिए आपको अपना कॉलबैक बनाने की आवश्यकता है। इसे प्राप्त करने के लिए, पहले आपको एक interface बनाने की आवश्यकता है:

public interface MyCallback {
    void onCallback(String value);
}

फिर आपको एक विधि बनाने की आवश्यकता है जो वास्तव में डेटाबेस से डेटा प्राप्त कर रही है। यह विधि इस तरह दिखनी चाहिए:

public void readData(MyCallback myCallback) {
    databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            String value = dataSnapshot.getValue(String.class);
            myCallback.onCallback(value);
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {}
    });
}

अंत में बस readData() विधि को कॉल करें और MyCallback इंटरफ़ेस के एक उदाहरण को एक तर्क के रूप में MyCallback करें जहाँ आपको इस तरह की आवश्यकता हो:

readData(new MyCallback() {
    @Override
    public void onCallback(String value) {
        Log.d("TAG", value);
    }
});

यह एकमात्र तरीका है जिसमें आप onDataChange() विधि के बाहर उस मान का उपयोग कर सकते हैं। अधिक जानकारी के लिए, आप इस video भी देख सकते हैं।


यहाँ एक पागल विचार है, onDataChange के अंदर, इसे दृश्यता के साथ TextView के अंदर रखें। Textview.setVisiblity textview.setVisiblity(Gone) गया textview.setVisiblity(Gone) या कुछ और, फिर कुछ ऐसा करें

textview.setText(dataSnapshot.getValue(String.class))

फिर बाद में इसे textview.getText().toString() साथ प्राप्त करें

बस एक आसान सा आइडिया।







firebase-realtime-database