5

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

यहाँ मेरी कोड है:

final Observable<CharSequence> email = RxTextView.textChanges(emailView); 

    Observable<Boolean> emailIsValid = email.map(new Func1<CharSequence, Boolean>() { 
     @Override 
     public Boolean call(CharSequence charSequence) { 
      Log.d("asdf", "emailIsValid call: " + charSequence); 
      return Pattern.matches(Patterns.EMAIL_ADDRESS.pattern(), charSequence); 
     } 
    }); 
    RxView.focusChanges(emailView) 
      .withLatestFrom(emailIsValid, new Func2<Boolean, Boolean, Boolean>() { 
       @Override 
       public Boolean call(Boolean hasFocus, Boolean emailIsValid) { 
        return (!hasFocus && !emailIsValid); 
       } 
      }) 
      .subscribe(new Action1<Boolean>() { 
       @Override 
       public void call(Boolean showError) { 
        if (showError) { 
         emailInputLayout.setError("Enter a valid email"); 
        } else { 
         emailInputLayout.setError(null); 
        } 
       } 
      }); 
    Observable<CharSequence> password = RxTextView.textChanges(passwordView); 

    Observable.combineLatest(emailIsValid, password, 
      new Func2<Boolean, CharSequence, Boolean>() { 
       @Override 
       public Boolean call(Boolean emailIsValid, CharSequence password) { 
        Log.d("asdf", "valid: " + emailIsValid + ", password: " + password); 
        return (emailIsValid && password.length() > 0); 
       } 
      }) 
      .subscribe(RxView.enabled(loginButton)); 

और यहाँ लॉग है:

emailIsValid call: emailIsValid call: valid: false, password: // I type 'j' emailIsValid call: j emailIsValid call: j valid: false, password: // I type 'a' emailIsValid call: ja emailIsValid call: ja valid: false, password:

आप देख सकते हैं, emailIsValid दो बार हर बार जब मैं एक चरित्र टाइप कहा जाता है, यह एक कर रहा है, जिसका मतलब है रेगेक्स मैच दो बार, जो अपमानजनक है।

मैंने देखा कि मैं emailIsValid केवल एक बार प्रति परिवर्तन कह सकता हूं, चाहे कितने ग्राहक हैं, और मुझे share() विधि मिली। यहाँ जब मैं emailIsValid की घोषणा के अंत तक .share() जोड़ने क्या होता है:

emailIsValid call: // I type 'j' emailIsValid call: j valid: false, password: // I type 'a' emailIsValid call: ja valid: false, password:

कि समस्या का हल है, लेकिन यह एक और कारण बनता है: कोई प्रारंभिक emailIsValid द्वारा अंत में combineLatest कार्य करने के लिए फेंकना है, इसलिए लॉगिन बटन सक्षम होना शुरू होता है, जब इसे अक्षम किया जाना चाहिए (ग्रेड आउट)।

इसे हल करने का सबसे साफ तरीका क्या है? मैं सोचता हूं मैं इसे BehaviorSubject की तरह व्यवहार करना चाहता हूं, लेकिन मुझे यकीन नहीं है कि यह करने का सबसे अच्छा तरीका है या नहीं।

उत्तर

1

आप publish() और connect() का उपयोग कर सकते हैं।

val email = RxTextView.textChanges(emailEditText) 
val emailIsValid = email.map { charSequence -> 
    Log.d("asdf", "emailIsValid call: " + charSequence) 
    Pattern.matches(Patterns.EMAIL_ADDRESS.pattern(), charSequence) 
}.publish() 
RxView.focusChanges(emailEditText) 
    .withLatestFrom(emailIsValid) { hasFocus, emailIsValid -> 
     (!hasFocus && !emailIsValid) 
    } 
    .subscribe { showError -> 
     if (showError) { 
     Log.d("asdf", "error") 
     } 
    } 
val password = RxTextView.textChanges(passwordEditText) 
Observable.combineLatest(emailIsValid, password) { emailIsValid, password -> 
    Log.d("asdf", "valid: $emailIsValid, password: $password") 
    (emailIsValid && password.length > 0) 
}.subscribe(RxView.enabled(button)) 
emailIsValid.connect() 

या बस अपने subscribe के आदेश को स्विच करें क्योंकि यह समस्या का कारण बनता है।

val email = RxTextView.textChanges(emailEditText) 
val emailIsValid = email.map { charSequence -> 
    Log.d("asdf", "emailIsValid call: " + charSequence) 
    Pattern.matches(Patterns.EMAIL_ADDRESS.pattern(), charSequence) 
}.share() 
val password = RxTextView.textChanges(passwordEditText) 
Observable.combineLatest(emailIsValid, password) { emailIsValid, password -> 
    Log.d("asdf", "valid: $emailIsValid, password: $password") 
    (emailIsValid && password.length > 0) 
}.subscribe(RxView.enabled(button)) 
RxView.focusChanges(emailEditText) 
    .withLatestFrom(emailIsValid) { hasFocus, emailIsValid -> 
     (!hasFocus && !emailIsValid) 
    } 
    .subscribe { showError -> 
     if (showError) { 
     Log.d("asdf", "error") 
     } 
    } 

नोट: कोड Kotlin और अधिक जानकारी में है के बारे में प्रकाशित/कनेक्ट है http://www.introtorx.com/content/v1.0.10621.0/14_HotAndColdObservables.html#PublishAndConnect

पर आपकी समस्या क्या PublishAndConnect अनुभाग .:

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

+0

बहुत बढ़िया, कनेक्ट करने योग्य अवलोकनों से अवगत नहीं था। अच्छा काम करता है, धन्यवाद! –

+0

@ D_Steve595 एनपी। खुशी है मैं मदद कर सकता हूँ! – pt2121

1

मुझे लगता है कि यहाँ क्या हो रहा है निम्नलिखित है:

  • पहले subscribe - RxView.focusChange()... के अंत में एक - emailIsValid (और इसलिए भी करने के लिए email) के लिए एक सदस्यता का कारण बनता है।

  • email तो तुरंत पहले Subscriber करने के लिए अपने पहले आइटम, जो बारी में emailIsValid और share माध्यम से चला जाता है और पर TextView की वर्तमान सामग्री उत्सर्जित करेगा (i। ई। withLatestFrom ऑपरेटर)।

  • कुछ समय बाद combineLatestemailIsValid पर एक और सदस्यता का कारण बनता है। चूंकि emailIsValidshare डी है, यह सदस्यता email पर "गुजरती" नहीं है और इसलिए प्रत्येक आइटम अभी भी एक बार उत्सर्जित हो जाएगा।

  • समस्या अब है कि share बर्ताव करता है एक PublishSubject की तरह है: यह सिर्फ सभी ग्राहकों के लिए भविष्य के किसी भी घटनाओं का उत्सर्जन करता है, लेकिन यह पिछले लोगों में से किसी को पुनः चलाने के नहीं है।

योग में इसका मतलब है: जब दूसरे Subscriber (combineLatest) आता है, प्रारंभिक मूल्य पिछले पहले से ही है - यह सही पहली सदस्यता के बाद उत्सर्जित किया गया था। और अगला मान केवल तभी आएगा जब आप TextView की सामग्री को बदल दें।

समाधान:emailIsValid के अंत में replay(1).refCount() बजाय share() का प्रयास करें - कि यह सुनिश्चित करना चाहिए कि प्रत्येक नए सब्सक्राइबर भी पिछले पिछले मूल्यांकन परिणाम है, साथ ही भविष्य की सभी लोगों को प्राप्त करता है।

मुझे उम्मीद है कि समस्या हल हो जाएगी और मेरी व्याख्या समझ में आती है।

संबंधित मुद्दे