निम्नलिखित सस्पेंड फ़ंक्शन 1 सेकंड की देरी में एक प्रगति पट्टी और 2 टेक्स्ट व्यू अपडेट कर रहा है। प्रोग्रेसबार एक एमपी3 और टेक्स्ट व्यू की क्रमशः बीता हुआ और शेष समय की प्रगति का संकेत दे रहा है।

उपयोगकर्ता टुकड़ा छोड़ सकता है और फिर से वापस आ सकता है, जिसका अर्थ है कि टुकड़ा (दृश्य) नष्ट हो जाता है और फिर से बनाया जाता है।

मैं सोच रहा था कि क्या यह कार्यान्वयन सही है और/या यदि बेहतर कार्यान्वयन और/या विकल्प हैं (पहली बार किसी कोरआउट को लागू करना)। यहाँ कुछ कोड है:

class BookViewFragment : Fragment(), CoroutineScope {
    private var _binding: FragmentBookViewerBinding? = null
    private val bookViewFragmentBinding get() = _binding!!

    private lateinit var job: Job
    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Main + job

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = FragmentBookViewerBinding.inflate(layoutInflater)
        val view = bookViewFragmentBinding.root
        job = Job()
        initMediaPlayer()
        return view
    }

    override fun onDestroyView() {
        super.onDestroyView()
        job.cancel()
        _binding = null
        mp.stop()
        mp.release()
    }

    private fun initMediaPlayer() {
        mp = MediaPlayer()

        mp.run {
            setDataSource(...)
            setVolume(0.5f, 0.5f)
            prepare()
        }
        totalTime = mp.duration
        initPositionBar()
    }

    private fun initPositionBar() {
        bookViewFragmentBinding.mediaPosition.max = totalTime

        launch {
            setTimeOnProgressBar()
        }
    }

    private suspend fun setTimeOnProgressBar() {
        coroutineScope {
            launch {
                var progress = mp.currentPosition
                while (progress < mp.duration) {
                    progress = mp.currentPosition
                    bookViewFragmentBinding.mediaPosition.progress = progress
                    val timePlayed = progress
                    val timeLeft = mp.duration - timePlayed
                    bookViewFragmentBinding.timePlayed.text = formatIntToTime(timePlayed)
                    bookViewFragmentBinding.timeLeft.text =
                        getString(R.string.time_left, formatIntToTime(timeLeft))
                    delay(1000)
                }
            }
        }
    }
}
1
Hooni 15 अप्रैल 2020, 15:57

1 उत्तर

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

यह सही लगता है, लेकिन आपने अपने लूप के चारों ओर coroutine की दो अनावश्यक परतें बना ली हैं। setTimeOnProgressBar() में, आपने अपने coroutine को एक नए coroutineScope में लपेट लिया है जिसका आप किसी भी चीज़ के लिए उपयोग नहीं करते हैं। इसे हटाया जा सकता है, और फिर यह बिल्कुल भी सस्पेंड फंक्शन नहीं होना चाहिए। और इसलिए आप उस कोरआउटिन को भी हटा सकते हैं जिसे आपने setTimeOnProgressBar() के साथ initPositionBar() में लपेटा है।

इसके अलावा, आपने बॉयलरप्लेट का एक गुच्छा फिर से बनाया है जो पहले से ही Android ktx लाइब्रेरी द्वारा प्रदान किया गया है। पहले से ही एक lifecycleScope एक्सटेंशन प्रॉपर्टी है जिसका उपयोग आप कोरटाइन लॉन्च करने के लिए कर सकते हैं, और यह onDestroyView() में स्वतः रद्द हो जाता है। इसलिए आपको पैरेंट जॉब बनाने या coroutineContext को ओवरराइड करने या पैरेंट जॉब को रद्द करने की आवश्यकता नहीं है।

कोरटाइन लॉन्च करते समय आप lifecycleScope.launch का उपयोग कर सकते हैं।

class BookViewFragment : Fragment() {
    private var _binding: FragmentBookViewerBinding? = null
    private val bookViewFragmentBinding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = FragmentBookViewerBinding.inflate(layoutInflater)
        val view = bookViewFragmentBinding.root
        initMediaPlayer()
        return view
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
        mp.stop()
        mp.release()
    }

    private fun initMediaPlayer() {
        mp = MediaPlayer()

        mp.run {
            setDataSource(...)
            setVolume(0.5f, 0.5f)
            prepare()
        }
        totalTime = mp.duration
        initPositionBar()
    }

    private fun initPositionBar() {
        bookViewFragmentBinding.mediaPosition.max = totalTime

        setTimeOnProgressBar()
    }

    private fun setTimeOnProgressBar() {
        lifecycleScope.launch {
            var progress = mp.currentPosition
            while (progress < mp.duration) {
                progress = mp.currentPosition
                bookViewFragmentBinding.mediaPosition.progress = progress
                val timePlayed = progress
                val timeLeft = mp.duration - timePlayed
                bookViewFragmentBinding.timePlayed.text = formatIntToTime(timePlayed)
                bookViewFragmentBinding.timeLeft.text =
                        getString(R.string.time_left, formatIntToTime(timeLeft))
                delay(1000)
            }
        }
    }
}
2
Tenfour04 15 अप्रैल 2020, 13:19