कोटलिन, आरएक्स, रेट्रोफिट2 में अपने कौशल में सुधार करने के लिए मैंने एक डेमो प्रोजेक्ट करने का फैसला किया है। डेमो प्रोजेक्ट में पोस्ट को रिसाइकलर व्यू में प्रदर्शित करना होता है और फिर पोस्ट के विवरण को विस्तृत गतिविधि में प्रदर्शित करना होता है।
मुझे विभिन्न एपीआई कॉल से आने वाले डेटा को प्रदर्शित करने में कठिनाइयों का सामना करना पड़ा: उपयोगकर्ता नाम, शीर्षक, पोस्ट का मुख्य भाग और पोस्ट की टिप्पणियों की संख्या।

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

एपीआई कॉल:
// पोस्ट के लिए टिप्पणियां लौटाएं 1
http://jsonplaceholder.typicode.com/comments?postId=1

// उपयोगकर्ता की जानकारी लौटाएं 2
http://jsonplaceholder.typicode.com/users/2

// मुख्य गतिविधि में पोस्ट प्रदर्शित करने के लिए उपयोग की जाने वाली कॉल
http://jsonplaceholder.typicode.com/posts

मैं अभी भी आरएक्स पर नया हूं, मैं एक फ्लैट मैप का उपयोग करने के बारे में सोच रहा था लेकिन मुझे नहीं पता कि कोटलिन में फ्लोएबल के साथ इसका उपयोग कैसे किया जाए ..

var post = viewModel.getPost()
var userStream: Flowable<User> = postService.getUser(post.userId)
var commentsByPostIdCall: Flowable<List<Comment>> = postService.getCommentsByPostId(post.id)

userStream.subscribeOn(Schedulers.io())
        .subscribe(object : Subscriber<User> {
            override fun onError(t: Throwable?) {
                Log.d(this.toString(), " Read of users failed with the following message: " + t?.message);
            }

            override fun onNext(user: User) {
                userTextView.text = user.name
                title.text = post.title
                body.text = post.body
            }

            override fun onComplete() {
            }

            override fun onSubscribe(s: Subscription?) {
                if (s != null) {
                    s.request(1)
                }
            }
        })

मैंने दूसरी कॉल को getNumberComments विधि में रखा है:

    private fun getNumberComments(commentsByPostIdCall: Flowable<List<Comment>>): Int {
    var listComments = listOf<Comment>()
    var listCommentSize = 0

     commentsByPostIdCall
             .subscribeOn(Schedulers.io())
             .subscribe(object : Subscriber<List<Comment>> {
                override fun onError(t: Throwable?) {
                    Log.d(this.toString(), " Read of comments failed with the following message: " + t?.message);
                }

                override fun onNext(comment: List<Comment>) {
                    listComments = comment
                }

                override fun onComplete() {
                    print("onComplete!")
                    listCommentSize = listComments.size
                }

                override fun onSubscribe(s: Subscription?) {
                    if (s != null) {
                        s.request(1)
                    }
                }
            })
    return listCommentSize

}

अन्य सोचते हैं कि मैंने देखा है कि कभी-कभी स्ट्रीम पूर्ण नहीं होती है, कभी-कभी यह अगला पर अवरुद्ध रहती है। समझ में नहीं आता क्यों?

किसी भी मदद की बहुत सराहना की जाएगी! बहुत - बहुत धन्यवाद :)

1
Hawa Zen 1 अगस्त 2017, 17:48

2 जवाब

सबसे बढ़िया उत्तर

इस तरह मैं इसे हल करूंगा:

Flowable.zip<User, Comments, Pair<User, Comments>>(
      postService.getUser(postId),
      postService.getCommentsByPostId(postId),
      BiFunction { user, comments -> Pair(user, comments) })
      .subscribeOn(Schedulers.io())
      .observeOn(AndroidSchedulers.mainThread())
      .bindToLifecycle(this)
      .map { (first, second) -> Triple(first, second, ExtraDatasFromSomewhere) }
      .subscribe({
        Log.d("MainActivity", "OnNext")
      }, {
        Log.d("MainActivity", "OnError")
      }, {
        Log.d("MainActivity", "OnComplete")
      })

अपने लक्ष्य को प्राप्त करने के लिए zip या zipWith फ़ंक्शन का उपयोग करें यदि रेट्रोफिट 2 कॉल एक दूसरे पर निर्भर नहीं हैं।
आप यहां और अधिक जानकारी प्राप्त कर सकते हैं:
आरएक्सज़िप (): http://reactivex.io/documentation/operators/zip

आप मुख्य गतिविधि डेटा के साथ सर्वर से डेटा को इस तरह आसानी से मैप कर सकते हैं:

.map { (first, second) -> Triple(first, second, ExtraDatasFromSomewhere) }

कोटलिन में लैम्ब्डा फ़ंक्शन के लिए एक बहुत ही सुंदर सिंटैक्स है, इसलिए मैं आपको विशिष्ट सदस्यता फ़ंक्शन के साथ उनका उपयोग करने के लिए प्रोत्साहित करूंगा:
सदस्यता लें (): http://reactivex.io/RxJava/javadoc/io/reactivex/Flowable.html#subscribe(io.reactivex.functions.Consumer,%20io.reactivex.functions.Consumer,%20io.reactivex.functions.Action)

यह भी नोट करना बहुत महत्वपूर्ण है कि मैंने केवल कच्चे Rxjava2 lib का उपयोग नहीं किया है। मैंने नीचे दिए गए libs का उपयोग किया: RxAndroid
observeOn(AndroidSchedulers.mainThread()) के लिए mainThread. ऐसा इसलिए है क्योंकि आपने अपने द्वारा सब्सक्राइब किए गए थ्रेड को निर्दिष्ट किए बिना UI में हेरफेर किया है। इससे आप यह हासिल कर सकते हैं कि आपकी सदस्यता मुख्य थ्रेड पर संचालित की जाएगी।
RxLifecycle
.bindToLifecycle(this) के लिए यह सुनिश्चित करेगा कि गतिविधि बंद होने पर आप स्मृति रिसाव नहीं छोड़ेंगे लेकिन आपकी रेट्रोफिट 2 कॉल समाप्त नहीं हुई है

3
Kioba 4 अगस्त 2017, 11:41

मैंने अभी अपनी जरूरतों के साथ Kioba द्वारा सुझाए गए समाधान को अनुकूलित किया है। मैं इसे यहां पोस्ट करता हूं अगर यह किसी के लिए उपयोगी हो सकता है। मुझे नहीं पता कि टिप्पणियों की संख्या प्राप्त करने का यह एक शानदार तरीका है या नहीं। मैंने अभी टिप्पणी के बजाय सूची <टिप्पणी> का उपयोग किया है और फिर मैं प्राप्त करने के लिए it.second.size.toString() जैसा कुछ करता हूं टिप्पणियों की संख्या।
चूंकि मुझे केवल दो डेटा चाहिए: उपयोगकर्ता और टिप्पणी मैंने ट्रिपल के बजाय जोड़ी का उपयोग करने का निर्णय लिया।

Flowable.zip<User, List<Comment>, Pair<User, List<Comment>>>(
            postService.getUser(post.id),
            postService.getCommentsByPostId(post.id),
            BiFunction { user, comments -> Pair(user, comments) })
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .map { (first, second) -> Pair(first, second) }
            .subscribe({
                Log.d("MainActivity", "OnNext")
                userTextView.text = it.first.name
                title.text = post.title
                body.text = post.body
                number_comments.text = it.second.size.toString()

            }, {
                Log.d("MainActivity", "OnError")
            }, {
                Log.d("MainActivity", "OnComplete")
            }) 
1
Hawa Zen 4 अगस्त 2017, 18:06