العمل مع طريقة العرض بشكل غير متزامن باستخدام coroutine

دعونا نلقي نظرة على موقف حيث لدينا عرض ، على سبيل المثال ، ImageView ، الذي يجب أن نعده أولاً قبل التقديم - على سبيل المثال ، حساب حجمه أو شكله أو تطبيق تأثير Blu-ray ، إلخ. يمكن أن تكون هذه الحسابات عملية مكلفة ، لذا من الأفضل نقلها إلى سلسلة المحادثات الخلفية.

سوف يقوم أجداد Javista بإنشاء ملف قابل للتشغيل ثم يستخدم المعالج لنقل النتيجة إلى التدفق الرئيسي واستخدامه في العرض (أول شيء يتبادر إلى الذهن).

كيف يمكن القيام بذلك بسرعة وسهولة في مرجل مع coroutines:

أولاً ، قم بإنشاء وظيفة امتداد kotlin:

inline fun <T> View.doAsync(
        crossinline backgroundTask: (scope: CoroutineScope) -> T, 
        crossinline result: (T?) -> Unit) {
    val job = CoroutineScope(Dispatchers.Main)
    //  ,    
    // ,   
    val attachListener = object : View.OnAttachStateChangeListener {
        override fun onViewAttachedToWindow(p0: View?) {}
        override fun onViewDetachedFromWindow(p0: View?) {
            job.cancel()
            removeOnAttachStateChangeListener(this)
        }
    }
    this.addOnAttachStateChangeListener(attachListener)
    //  Job,      
    job.launch {
        //  Deferred     
        val data = async(Dispatchers.Default) {
            try {
                backgroundTask(this)
            } catch (e: Exception) {
                e.printStackTrace()
                return@async null
            }
        }
        if (isActive) {
            try {
                result.invoke(data.await())
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
        //     Job
        this@doAsync.removeOnAttachStateChangeListener(attachListener)
    }
}

الآن سنقوم بمحاكاة موقف: لدينا RecyclerView ، في كل عنصر هناك صورة. قبل العرض ، نريد طمس هذه الصورة (طمس). إليك كيف ستكون بدون التزامن:

inner class PostHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    private val ivTest = itemView.iv_test
    fun bind() {
        val bitmap = ... 
        val blurBitmap = bitmap?.addBlurShadow(Color.CYAN, 50.dp, 50.dp)
        ivTest.setImageBitmap(blurBitmap)
    }
}

النتيجة:



كما ترون ، فإن خسارة الموظفين كبيرة.

الآن نستخدم وظيفتنا:

inner class PostHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    private val ivTest = itemView.iv_test
    fun bind() {
        val bitmap = ... 
        itemView.doAsync({ scope -> 
            //        
            return@doAsync bitmap?.addBlurShadow(Color.CYAN, 50.dp, 50.dp)
        }, { it ->
            //            
            ivTest.setImageBitmap(it)
        })
    }
}

النتيجة:



الأمر برمته هو أننا مرتبطون بدورة حياة المنظر. لذلك ، عندما يتم فصل العرض عن الأصل ، ويحدث هذا باستمرار في وحدة إعادة التدوير عند فقدان العنصر ، أو في الجزء / النشاط عندما يتم تدميرها ، يمكننا إيقاف وإلغاء coroutine بأمان ، مع العلم أنه لا يوجد مكان لعرض النتيجة ، يكون العرض جاهزًا للتدمير.

لجعلها واضحة ومفهومة ، أوصي بكتابة مثل هذا الرمز في ViewHolder الخاص بك والنظر في السجلات:

itemView.doAsync({ scope ->
    logInfo("coroutine start")
    var x = 0
    //        scope.isActive
    //       isActive = true,     
    //    ,     
    while (x < 100 && scope.isActive) {
        TimeUnit.MILLISECONDS.sleep(100)
        logInfo("coroutine, position: $adapterPosition ${x++}")
    }
    logInfo("coroutine end")
}, {
    logInfo("coroutine DONE")
})

وسترى على أي حامل عرض أي روتين يبدأ العمل ، والذي يتم إلغاؤه ويتوقف عن العمل.

All Articles