मेरे पास एक तृतीय पक्ष लाइब्रेरी है जो वीडियो में वर्तमान स्थिति जैसी जानकारी के लिए समय-समय पर मेरे वीडियो प्लेयर (एक्सोप्लेयर) से पूछताछ करती है। यह थर्ड पार्टी लाइब्रेरी बैकग्राउंड थ्रेड पर चलती है। समस्या यह है कि एक्सोप्लेयर इंस्टेंस को पृष्ठभूमि थ्रेड द्वारा एक्सेस करने की अनुमति नहीं है।

मेरे विचारों में से एक एक्सोप्लेयर इंस्टेंस तक पहुंचने से पहले मुख्य धागे पर स्विच करने के लिए कोरआउटिन का उपयोग करना था। ऐसा कुछ (ध्यान दें कि इसे मुख्य और पृष्ठभूमि धागे दोनों पर कई स्थानों से बुलाया जाता है):

suspend fun getCurrentPosition(): Long {
    if (Looper.myLooper() != Looper.getMainLooper()) {
        // On a background thread, switch to main thread and return current position
        return withContext(Dispatchers.Main) {
            exoPlayerInstance.currentPosition
        }
    } else {
        // Already on main thread, no need to switch threads
        return exoPlayerInstance.currentPosition
    }
}

तब मैं इसे रनब्लॉकिंग के साथ इस प्रकार कॉल करूंगा:

runBlocking { videoPlayerWrapper.getCurrentPosition() }

रनब्लॉकिंग का उपयोग किया जाता है क्योंकि तृतीय पक्ष पुस्तकालय तत्काल परिणाम की अपेक्षा करता है।

यह कभी-कभी काम करता है लेकिन दूसरी बार मेरा ऐप पूरी तरह से लॉक हो जाता है। कोई विचार क्या गलत हो सकता है? कोई वैकल्पिक समाधान?

1
SilentByte 9 जिंदा 2020, 01:25

2 जवाब

तब मैं इसे रनब्लॉकिंग के साथ इस प्रकार कॉल करूंगा:

रनब्लॉकिंग { videoPlayerWrapper.getCurrentPosition() }

परिभाषा के अनुसार runBlocking वर्तमान Thread को तब तक ब्लॉक कर देगा, जब तक कि coroutine पूरा नहीं हो जाता। runBlocking दस्तावेज़ों से :

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

इसका प्रभावी अर्थ यह है कि यदि आप runBlocking को मुख्य Thread से कॉल कर रहे हैं तो आपका UI फ्रीज हो जाएगा। मेरा अनुमान है कि कभी-कभी videoPlayerWrapper.getCurrentPosition() इतनी तेजी से लौटता है कि आपको पता ही नहीं चलता कि यह वास्तव में अवरुद्ध है।

यह थर्ड पार्टी लाइब्रेरी बैकग्राउंड थ्रेड पर चलती है। समस्या यह है कि एक्सोप्लेयर इंस्टेंस को पृष्ठभूमि थ्रेड द्वारा एक्सेस करने की अनुमति नहीं है।

मुझे ऐसा लगता है कि यहाँ एक डिज़ाइन दोष है। पुस्तकालय के बजाय Exoplayer उदाहरण पर पकड़ बनाने की कोशिश करने के बजाय, पुस्तकालय को उपभोक्ता को स्थिति प्रदान करने के लिए एक अनुबंध स्थापित करना चाहिए। यदि कोरआउटिन का उपयोग करते हैं, तो पुस्तकालय को एक Flow<Int> की आवश्यकता हो सकती है जो स्थिति में परिवर्तन के रूप में वर्तमान स्थिति को उत्सर्जित करता है।

0
Emmanuel 9 जिंदा 2020, 02:01
पुस्तकालय दोष पर सहमत हूँ, हालाँकि यह मेरे हाथ से बाहर है। पुस्तकालय के लिए आपको इसे एक इंटरफ़ेस के कार्यान्वयन को पारित करने की आवश्यकता होती है जिसमें विधि परिभाषाएं होती हैं जैसे: "fun getVideoPosition(): Long"। मुझे अभी भी समझ में नहीं आया कि मेरा UI थ्रेड उपरोक्त कोड के साथ गतिरोध क्यों कर रहा है।
 – 
SilentByte
9 जिंदा 2020, 03:07
आप runBlocking{} को कहां से कॉल कर रहे हैं? किस Thread से?
 – 
Emmanuel
9 जिंदा 2020, 03:47
मुझे नहीं लगता कि Looper चेक बहुत अधिक मूल्य जोड़ता है क्योंकि withContext(Dispatchers.Main) सुनिश्चित करता है कि आप मुख्य Thread पर स्विच कर चुके हैं और यदि आप पहले से ही मुख्य Thread पर हैं तो कोई संदर्भ नहीं है स्विच। मेरा मतलब यह है कि withContext(Dispatchers.Main){exoPlayerInstance.currentPosition} लौटना पर्याप्त होना चाहिए। जहां तक ​​​​यूआई फ्रीजिंग क्यों है, फिर से, runBlocking{} को मुख्य कार्यों या परीक्षणों के दौरान उपयोग करने का इरादा है क्योंकि यह Thread को अवरुद्ध करता है जिससे इसे कहा जाता है।
 – 
Emmanuel
9 जिंदा 2020, 04:04
मेरा जवाब बदल रहा है... रनब्लॉकिंग को पृष्ठभूमि और मुख्य दोनों से बुलाया जा सकता है। मुझे सुबह दोबारा जांच करनी होगी। निश्चित रूप से कम से कम पृष्ठभूमि से हालांकि।
 – 
SilentByte
9 जिंदा 2020, 04:06
मैं समझता हूं कि रनब्लॉकिंग वर्तमान धागे को अवरुद्ध करता है। लेकिन इसे तब तक ब्लॉक करना चाहिए जब तक कि काम पूरा न हो जाए। और वास्तव में यहाँ कोई अवरुद्ध कार्य नहीं है। यह सिर्फ एक मूल्य लौटा रहा है।
 – 
SilentByte
9 जिंदा 2020, 04:09

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

  fun getCurrentPosition() = runBlocking(Dispatchers.Main.immediate) {
      exoPlayerInstance.currentPosition
  }

Dispatchers.Main.immediate केवल तभी संदर्भ स्विच करता है जब वर्तमान धागा मुख्य धागा नहीं है।

1
Pierluigi 10 जिंदा 2020, 22:06