From 1d88941b63fbd3de9d420ed44dca9caafe45fcf2 Mon Sep 17 00:00:00 2001 From: Christophe Beyls Date: Tue, 21 Apr 2020 14:42:36 +0200 Subject: [PATCH] create viewLifecycleLazy and use it to make fragments properly implement RecycledViewPoolProvider --- .../fosdem/fragments/LiveFragment.kt | 8 +++-- .../fragments/RecycledViewPoolProvider.kt | 2 +- .../fosdem/fragments/TracksFragment.kt | 12 +++---- .../be/digitalia/fosdem/utils/FragmentExt.kt | 31 +++++++++++++++++++ 4 files changed, 41 insertions(+), 12 deletions(-) create mode 100644 app/src/main/java/be/digitalia/fosdem/utils/FragmentExt.kt diff --git a/app/src/main/java/be/digitalia/fosdem/fragments/LiveFragment.kt b/app/src/main/java/be/digitalia/fosdem/fragments/LiveFragment.kt index 54f410e..ae20f80 100644 --- a/app/src/main/java/be/digitalia/fosdem/fragments/LiveFragment.kt +++ b/app/src/main/java/be/digitalia/fosdem/fragments/LiveFragment.kt @@ -3,12 +3,13 @@ package be.digitalia.fosdem.fragments import android.os.Bundle import android.view.View import androidx.fragment.app.Fragment -import androidx.recyclerview.widget.RecyclerView.RecycledViewPool +import androidx.recyclerview.widget.RecyclerView import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.widget.ViewPager2 import be.digitalia.fosdem.R import be.digitalia.fosdem.utils.enforceSingleScrollDirection import be.digitalia.fosdem.utils.recyclerView +import be.digitalia.fosdem.utils.viewLifecycleLazy import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayoutMediator import com.google.android.material.tabs.TabLayoutMediator.TabConfigurationStrategy @@ -37,8 +38,9 @@ class LiveFragment : Fragment(R.layout.fragment_live), RecycledViewPoolProvider } } - override var recycledViewPool: RecycledViewPool? = null - private set + override val recycledViewPool by viewLifecycleLazy { + RecyclerView.RecycledViewPool() + } private class LivePagerAdapter(fragment: Fragment) : FragmentStateAdapter(fragment.childFragmentManager, fragment.viewLifecycleOwner.lifecycle) { diff --git a/app/src/main/java/be/digitalia/fosdem/fragments/RecycledViewPoolProvider.kt b/app/src/main/java/be/digitalia/fosdem/fragments/RecycledViewPoolProvider.kt index dda80bd..92990d4 100644 --- a/app/src/main/java/be/digitalia/fosdem/fragments/RecycledViewPoolProvider.kt +++ b/app/src/main/java/be/digitalia/fosdem/fragments/RecycledViewPoolProvider.kt @@ -6,5 +6,5 @@ import androidx.recyclerview.widget.RecyclerView * Components implementing this interface allow to share a RecycledViewPool between similar fragments. */ interface RecycledViewPoolProvider { - val recycledViewPool: RecyclerView.RecycledViewPool? + val recycledViewPool: RecyclerView.RecycledViewPool } \ No newline at end of file diff --git a/app/src/main/java/be/digitalia/fosdem/fragments/TracksFragment.kt b/app/src/main/java/be/digitalia/fosdem/fragments/TracksFragment.kt index ba4e497..2795048 100644 --- a/app/src/main/java/be/digitalia/fosdem/fragments/TracksFragment.kt +++ b/app/src/main/java/be/digitalia/fosdem/fragments/TracksFragment.kt @@ -9,7 +9,7 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.observe -import androidx.recyclerview.widget.RecyclerView.RecycledViewPool +import androidx.recyclerview.widget.RecyclerView import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.widget.ViewPager2 import be.digitalia.fosdem.R @@ -17,6 +17,7 @@ import be.digitalia.fosdem.db.AppDatabase import be.digitalia.fosdem.model.Day import be.digitalia.fosdem.utils.enforceSingleScrollDirection import be.digitalia.fosdem.utils.recyclerView +import be.digitalia.fosdem.utils.viewLifecycleLazy import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayoutMediator import com.google.android.material.tabs.TabLayoutMediator.TabConfigurationStrategy @@ -40,7 +41,6 @@ class TracksFragment : Fragment(R.layout.fragment_tracks), RecycledViewPoolProvi } } val daysAdapter = DaysAdapter(this) - recycledViewPool = RecycledViewPool() var savedCurrentPage = if (savedInstanceState == null) { // Restore the current page from preferences @@ -86,14 +86,10 @@ class TracksFragment : Fragment(R.layout.fragment_tracks), RecycledViewPoolProvi }) } - override fun onDestroyView() { - super.onDestroyView() - recycledViewPool = null + override val recycledViewPool by viewLifecycleLazy { + RecyclerView.RecycledViewPool() } - override var recycledViewPool: RecycledViewPool? = null - private set - private class DaysAdapter(fragment: Fragment) : FragmentStateAdapter(fragment.childFragmentManager, fragment.viewLifecycleOwner.lifecycle) { diff --git a/app/src/main/java/be/digitalia/fosdem/utils/FragmentExt.kt b/app/src/main/java/be/digitalia/fosdem/utils/FragmentExt.kt new file mode 100644 index 0000000..2e7f2b0 --- /dev/null +++ b/app/src/main/java/be/digitalia/fosdem/utils/FragmentExt.kt @@ -0,0 +1,31 @@ +package be.digitalia.fosdem.utils + +import androidx.fragment.app.Fragment +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver + +/** + * A Lazy implementation which can only be called when a fragment has a view + * and will automatically clear the value when the view hierarchy gets destroyed. + */ +fun Fragment.viewLifecycleLazy(initializer: () -> T): Lazy = ViewLifecycleLazy(this, initializer) + +class ViewLifecycleLazy(private val fragment: Fragment, private val initializer: () -> T) : Lazy { + private var cached: T? = null + + override val value: T + get() { + return cached ?: run { + val newValue = initializer() + cached = newValue + fragment.viewLifecycleOwner.lifecycle.addObserver(LifecycleEventObserver { _, event -> + if (event == Lifecycle.Event.ON_DESTROY) { + cached = null + } + }) + newValue + } + } + + override fun isInitialized() = cached != null +} \ No newline at end of file