<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          再談協(xié)程之Lifecycle潛行者

          共 9909字,需瀏覽 20分鐘

           ·

          2021-10-28 23:21

          0da734d7007193abef2263e095596c50.webp

          點(diǎn)擊上方藍(lán)字關(guān)注我,知識(shí)會(huì)給你力量

          572f83594328e5b482458278ad46b993.webp

          Lifecycle

          國(guó)際慣例,官網(wǎng)鎮(zhèn)樓

          https://developer.android.com/topic/libraries/architecture/lifecycle

          關(guān)于Lifecycle的基本使用,這里就不詳細(xì)介紹了,畢竟官網(wǎng)講的很清楚了,而且大部分時(shí)間,我們也用太感知細(xì)節(jié),這也是JetPack的魅力所在。

          Lifecycle作為JetPack的核心組件之一,在JetPack的多個(gè)組件中都扮演著非常重要的角色。

          大部分時(shí)候,我們?cè)谑褂肑etPack的組件時(shí),都不需要特別考慮Lifecycle,這得益于大部分JetPack組件的Lifecycle Aware特性,類(lèi)似lifecycleScope、ViewModelScope都可以在生命周期結(jié)束時(shí),自動(dòng)對(duì)資源進(jìn)行釋放,可以說(shuō),Lifecycle是JetPack組件的脊梁,而且大部分時(shí)間,可以開(kāi)箱即用,不用做太多配置就可以直接掌控生命周期。

          Activity可以作為L(zhǎng)ifecycleOwner,在AAC架構(gòu)中扮演著重要的作用,那么Activity是怎么關(guān)聯(lián)Lifecycle的呢?

          AppCompatActivity繼承自FragmentActivity,F(xiàn)ragmentActivity繼承自ComponentActivity,在ComponentActivity中,通過(guò)LifecycleRegistry來(lái)關(guān)聯(lián)生命周期,但是ComponentActivity并沒(méi)有直接處理生命周期,而是通過(guò)ReportFragment來(lái)進(jìn)行代理。

          在ComponentActivity的onCreate中,對(duì)ReportFragment進(jìn)行了初始化,代碼如下所示。

          ReportFragment.injectIfNeededIn(this);

          在ReportFragment中,對(duì)不同版本做了兼容處理:

          8f6d495e9f0d2d7aa8886f62feb352ab.webpimage-20210915161754312

          在ReportFragment中,通過(guò)activity.getLifecycle()來(lái)獲取Activity中申明的LifecycleRegistry,并對(duì)生命周期進(jìn)行管理。

          在App初始化的時(shí)候,Android利用ContentProvider來(lái)初始化ProcessLifecycleOwnerInitializer,在這里,又會(huì)對(duì)LifecycleDispatcher和ProcessLifecycleOwner中的ActivityInitializationListener進(jìn)行初始化,從而實(shí)現(xiàn)生命周期的感知。

          ?

          細(xì)心的讀者可能發(fā)現(xiàn)了,這里使用的是已經(jīng)被廢棄的android.app.Fragment,其原因就是為了兼容舊版本的Fragment所做的妥協(xié)。

          ?

          lifecycleScope

          lifecycleScope是Lifecycle的拓展函數(shù),是Lifecycle對(duì)協(xié)程的支持,所以要使用lifecycleScope必須要先引入Lifecycle。

          lifecycleScope也是CoroutineScope,所以也支持launch函數(shù)來(lái)構(gòu)建,但是lifecycleScope提供了更加精確的,帶生命周期的創(chuàng)建函數(shù),如下所示。

          lifecycleScope.launchWhenCreated{}
          lifecycleScope.launchWhenStarted{}
          lifecycleScope.launchWhenResumed{}

          分別對(duì)應(yīng)Activity的生命周期。

          lifecycleScope可以直接使用,也可以針對(duì)特定的生命周期控制,一般寫(xiě)法有如下兩種。

          • 直接使用
          lifecycleScope.launch {
              XXXX
          }
          • 帶特定生命周期控制,有兩種方式
          // 方式1
          lifecycleScope.launchWhenStarted {
            XXX
          }
          // 方式2
          lifecycleScope.launch {
              whenStarted {
             XXX
              }
          }

          lifecycleScope能自動(dòng)取消協(xié)程,避免泄漏的原理其實(shí)非常簡(jiǎn)單,就是在Lifecycle的生命周期回調(diào)中,在onDestroy中對(duì)協(xié)程做Cancel操作。

          f648f906151e84b1039478ccfa521e97.webpimage-20210728173437294

          lifecycleScope的這種處理方式具有很強(qiáng)的指導(dǎo)意義,我們?cè)谄綍r(shí)的代碼實(shí)現(xiàn)中,都可以借用這種方式來(lái)對(duì)生命周期進(jìn)行自動(dòng)管理。

          普通組件感知生命周期

          普通的組件是無(wú)法感知生命周期的,但是借助Lifecycle,我們就可以很輕松的為任意組件增加對(duì)生命周期的感知,其原理實(shí)際上就是對(duì)普通組件增加LifecycleEventObserver的實(shí)現(xiàn),這樣在LifecycleOwner的生命周期發(fā)生改變時(shí),就能在onStateChanged中獲取對(duì)應(yīng)的生命周期變化了,代碼如下所示。

          @SuppressLint("ViewConstructor")
          class LifecycleAwareView @JvmOverloads constructor(
              context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, lifecycleOwner: LifecycleOwner
          ) : View(context, attrs, defStyleAttr), LifecycleEventObserver {

              init {
                  // Do something init
                  Log.d("xys""Init-------")
                  lifecycleOwner.lifecycle.addObserver(this)
              }

              private fun release() {
                  // Do something release
                  Log.d("xys""Release-------")
              }

              override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
                  when (event) {
                      Lifecycle.Event.ON_DESTROY -> {
                          release()
                          source.lifecycle.removeObserver(this)
                      }
                  }
              }
          }

          如上所示,這是一個(gè)非常簡(jiǎn)單的自定義View,只不過(guò)實(shí)現(xiàn)了LifecycleEventObserver接口,并在init的時(shí)候增加監(jiān)聽(tīng),并對(duì)onStateChanged做了處理,增加了View在生命周期結(jié)束時(shí)的處理。

          調(diào)用如下。

          binding.root.addView(LifecycleAwareView(this, lifecycleOwner = this))

          傳入對(duì)應(yīng)的LifecycleOwner即可。

          Lifecycle in RecyclerView

          比較常見(jiàn)的LifecycleOwner是Activity和Fragment,通常我們也是以這兩個(gè)作為程序運(yùn)行的承載界面,將生命周期與它們綁定是合理的,但在RecyclerView的場(chǎng)景下,這個(gè)界面生命周期的粒度就有些太粗了,如果我們?cè)谀硞€(gè)ViewHolder中發(fā)起網(wǎng)絡(luò)請(qǐng)求,當(dāng)這個(gè)ViewHolder被回收,那么這個(gè)請(qǐng)求在未處理的情況下,就會(huì)導(dǎo)致內(nèi)存泄漏,所以通常的做法是ViewHolder的事件通過(guò)回調(diào)的方式托管到Activity,這樣的方式,在業(yè)務(wù)開(kāi)發(fā)場(chǎng)景下,是合理的,但是卻不利于業(yè)務(wù)組件的封裝。

          首先,將業(yè)務(wù)邏輯回調(diào)到Activity,業(yè)務(wù)組件就只能以Activity作為使用范圍,無(wú)法更加精細(xì)的控制組件粒度。

          其次,回調(diào)托管寫(xiě)起來(lái)也比較麻煩。

          所以,如果能自動(dòng)管理ViewHolder的生命周期,那么就可以以ViewHolder,甚至是其中的View來(lái)作為業(yè)務(wù)組件的粒度劃分,這樣可以將業(yè)務(wù)邏輯統(tǒng)一處理而不用擔(dān)心內(nèi)存泄漏,而且業(yè)務(wù)方在使用時(shí),可以直接黑盒使用某個(gè)業(yè)務(wù)組件,不必關(guān)心其中的邏輯。

          ?

          當(dāng)然這種處理也是要分場(chǎng)景考慮的,其中一個(gè)重點(diǎn)就是這個(gè)組件是偏業(yè)務(wù)還是偏功能,也就是是否要將業(yè)務(wù)邏輯統(tǒng)一包進(jìn)組件,想清楚這個(gè)問(wèn)題后,才能去開(kāi)發(fā)一個(gè)業(yè)務(wù)組件。

          ?

          那么我們?nèi)绾蝸?lái)控制一個(gè)View的生命周期呢?

          View其實(shí)提供了一個(gè)OnAttachStateChangeListener,可以回調(diào)View的onViewAttachedToWindow和onViewDetachedFromWindow,這就可以作為View的生命周期監(jiān)控,再利用協(xié)程的CompletionHandler,來(lái)獲得協(xié)程執(zhí)行完成的回調(diào),就可以對(duì)View的生命周期做處理了,代碼如下所示。

          private class ViewStateListener(
              private val view: View,
              private val job: Job
          ) : View.OnAttachStateChangeListener, CompletionHandler {
              override fun onViewDetachedFromWindow(v: View) {
                  view.removeOnAttachStateChangeListener(this)
                  Log.d("xys""release")
                  job.cancel()
              }

              override fun onViewAttachedToWindow(v: View) {}

              override fun invoke(cause: Throwable?) {
                  view.removeOnAttachStateChangeListener(this)
                  job.cancel()
              }
          }

          接下來(lái),我們通過(guò)協(xié)程攔截器,在協(xié)程執(zhí)行前,注入對(duì)View的監(jiān)聽(tīng),代碼如下所示。

          private class ViewAutoDisposeInterceptor(
              private val view: View
          ) : ContinuationInterceptor {
              override val key: CoroutineContext.Key<*>
                  get() = ContinuationInterceptor

              override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> {
                  val job = continuation.context[Job]
                  if (job != null) {
                      view.addOnAttachStateChangeListener(ViewStateListener(view, job))
                  }
                  return continuation
              }
          }

          最后,我們創(chuàng)建一個(gè)拓展函數(shù),給View返回一個(gè)協(xié)程作用域,這個(gè)協(xié)程作用域可以在Viewdetached的時(shí)候,自動(dòng)cancel協(xié)程的執(zhí)行,從而避免內(nèi)存泄漏,代碼如下所示。

          private const val TAG = R.id.autodispose_view_tag

          val View.autoDisposeScope: CoroutineScope
              get() {
                  val exist = getTag(TAG) as? CoroutineScope
                  if (exist != null) {
                      return exist
                  }
                  val newScope = CoroutineScope(
                      SupervisorJob() +
                              Dispatchers.Main +
                              ViewAutoDisposeInterceptor(this)
                  )
                  setTag(TAG, newScope)
                  return newScope
              }

          這里給View設(shè)置了Tag,從而可以更好的利用緩存。

          有了View、ViewHolder的生命周期管理,就可以很好的將耗時(shí)業(yè)務(wù)邏輯的處理封裝到View、ViewHolder中,示例代碼如下所示。

          internal class SampleAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
              override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
                  object : RecyclerView.ViewHolder(TextView(parent.context)) {}

              override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
                  (holder.itemView as TextView).text = position.toString()
                  val job = holder.itemView.autoDisposeScope.launch {
                      delay(1000)
                      Log.d("xys""success $position")
                  }
                  job.invokeOnCompletion {
                      Log.d("xys""complete $position")
                  }
              }

              override fun getItemCount(): Int = 300
          }

          這樣就可以對(duì)任意View、ViewHolder創(chuàng)建自適應(yīng)生命周期管理的協(xié)程作用域,從而實(shí)現(xiàn)autoDispose的功能。

          向大家推薦下我的網(wǎng)站 https://xuyisheng.top/  點(diǎn)擊原文一鍵直達(dá)

          專(zhuān)注 Android-Kotlin-Flutter 歡迎大家訪問(wèn)



          往期推薦


          本文原創(chuàng)公眾號(hào):群英傳,授權(quán)轉(zhuǎn)載請(qǐng)聯(lián)系微信(Tomcat_xu),授權(quán)后,請(qǐng)?jiān)谠瓌?chuàng)發(fā)表24小時(shí)后轉(zhuǎn)載。< END >作者:徐宜生

          更文不易,點(diǎn)個(gè)“三連”支持一下??


          瀏覽 104
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  射av在线 | www.操操操.com | 91视频搞靠逼 | 亚洲色俺来也 | 日韩AⅤ无码一区二区三区 |