From 8cd1a0cb384e23de6a41d19302e46f409e495121 Mon Sep 17 00:00:00 2001 From: Tiger Oakes Date: Mon, 1 Jul 2019 14:34:25 -0400 Subject: [PATCH] Move adapter Job setup code to helper class (#3407) --- .../CollectionCreationTabListAdapter.kt | 16 ++----- .../collections/SaveCollectionListAdapter.kt | 16 ++----- .../fenix/exceptions/ExceptionsAdapter.kt | 17 ++----- .../sessioncontrol/SessionControlAdapter.kt | 23 ++------- .../library/bookmarks/BookmarkAdapter.kt | 21 ++------ .../fenix/library/history/HistoryAdapter.kt | 20 ++------ .../org/mozilla/fenix/share/AppShareView.kt | 17 ++----- .../org/mozilla/fenix/utils/AdapterWithJob.kt | 48 +++++++++++++++++++ 8 files changed, 74 insertions(+), 104 deletions(-) create mode 100644 app/src/main/java/org/mozilla/fenix/utils/AdapterWithJob.kt diff --git a/app/src/main/java/org/mozilla/fenix/collections/CollectionCreationTabListAdapter.kt b/app/src/main/java/org/mozilla/fenix/collections/CollectionCreationTabListAdapter.kt index 3e3bebfdf..af1d816d3 100644 --- a/app/src/main/java/org/mozilla/fenix/collections/CollectionCreationTabListAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/collections/CollectionCreationTabListAdapter.kt @@ -19,21 +19,21 @@ import mozilla.components.browser.icons.IconRequest import org.mozilla.fenix.R import org.mozilla.fenix.ext.components import org.mozilla.fenix.home.sessioncontrol.Tab +import org.mozilla.fenix.utils.AdapterWithJob import kotlin.coroutines.CoroutineContext class CollectionCreationTabListAdapter( val actionEmitter: Observer -) : RecyclerView.Adapter() { +) : AdapterWithJob() { private var tabs: List = listOf() private var selectedTabs: MutableSet = mutableSetOf() - private lateinit var job: Job private var hideCheckboxes = false override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TabViewHolder { val view = LayoutInflater.from(parent.context).inflate(TabViewHolder.LAYOUT_ID, parent, false) - return TabViewHolder(view, job) + return TabViewHolder(view, adapterJob) } override fun onBindViewHolder(holder: TabViewHolder, position: Int, payloads: MutableList) { @@ -73,16 +73,6 @@ class CollectionCreationTabListAdapter( override fun getItemCount(): Int = tabs.size - override fun onAttachedToRecyclerView(recyclerView: RecyclerView) { - super.onAttachedToRecyclerView(recyclerView) - job = Job() - } - - override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) { - super.onDetachedFromRecyclerView(recyclerView) - job.cancel() - } - fun updateData(tabs: List, selectedTabs: Set, hideCheckboxes: Boolean = false) { val diffUtil = DiffUtil.calculateDiff( TabDiffUtil( diff --git a/app/src/main/java/org/mozilla/fenix/collections/SaveCollectionListAdapter.kt b/app/src/main/java/org/mozilla/fenix/collections/SaveCollectionListAdapter.kt index df400ecd9..2114c8a34 100644 --- a/app/src/main/java/org/mozilla/fenix/collections/SaveCollectionListAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/collections/SaveCollectionListAdapter.kt @@ -19,13 +19,13 @@ import org.mozilla.fenix.R import org.mozilla.fenix.components.description import org.mozilla.fenix.home.sessioncontrol.Tab import org.mozilla.fenix.home.sessioncontrol.TabCollection +import org.mozilla.fenix.utils.AdapterWithJob import kotlin.coroutines.CoroutineContext class SaveCollectionListAdapter( val actionEmitter: Observer -) : RecyclerView.Adapter() { +) : AdapterWithJob() { - private lateinit var job: Job private var tabCollections = listOf() private var selectedTabs: Set = setOf() @@ -33,7 +33,7 @@ class SaveCollectionListAdapter( val view = LayoutInflater.from(parent.context) .inflate(CollectionViewHolder.LAYOUT_ID, parent, false) - return CollectionViewHolder(view, actionEmitter, job) + return CollectionViewHolder(view, actionEmitter, adapterJob) } override fun onBindViewHolder(holder: CollectionViewHolder, position: Int) { @@ -49,16 +49,6 @@ class SaveCollectionListAdapter( override fun getItemCount(): Int = tabCollections.size - override fun onAttachedToRecyclerView(recyclerView: RecyclerView) { - super.onAttachedToRecyclerView(recyclerView) - job = Job() - } - - override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) { - super.onDetachedFromRecyclerView(recyclerView) - job.cancel() - } - fun updateData(tabCollections: List, selectedTabs: Set) { this.tabCollections = tabCollections this.selectedTabs = selectedTabs diff --git a/app/src/main/java/org/mozilla/fenix/exceptions/ExceptionsAdapter.kt b/app/src/main/java/org/mozilla/fenix/exceptions/ExceptionsAdapter.kt index 807dbb536..32e708ae4 100644 --- a/app/src/main/java/org/mozilla/fenix/exceptions/ExceptionsAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/exceptions/ExceptionsAdapter.kt @@ -8,10 +8,10 @@ import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import io.reactivex.Observer -import kotlinx.coroutines.Job import org.mozilla.fenix.exceptions.viewholders.ExceptionsDeleteButtonViewHolder import org.mozilla.fenix.exceptions.viewholders.ExceptionsHeaderViewHolder import org.mozilla.fenix.exceptions.viewholders.ExceptionsListItemViewHolder +import org.mozilla.fenix.utils.AdapterWithJob private sealed class AdapterItem { object DeleteButton : AdapterItem() @@ -34,9 +34,8 @@ private class ExceptionsList(val exceptions: List) { class ExceptionsAdapter( private val actionEmitter: Observer -) : RecyclerView.Adapter() { +) : AdapterWithJob() { private var exceptionsList: ExceptionsList = ExceptionsList(emptyList()) - private lateinit var job: Job fun updateData(items: List) { this.exceptionsList = ExceptionsList(items) @@ -59,7 +58,7 @@ class ExceptionsAdapter( return when (viewType) { ExceptionsDeleteButtonViewHolder.LAYOUT_ID -> ExceptionsDeleteButtonViewHolder(view, actionEmitter) ExceptionsHeaderViewHolder.LAYOUT_ID -> ExceptionsHeaderViewHolder(view) - ExceptionsListItemViewHolder.LAYOUT_ID -> ExceptionsListItemViewHolder(view, actionEmitter, job) + ExceptionsListItemViewHolder.LAYOUT_ID -> ExceptionsListItemViewHolder(view, actionEmitter, adapterJob) else -> throw IllegalStateException() } } @@ -71,14 +70,4 @@ class ExceptionsAdapter( } } } - - override fun onAttachedToRecyclerView(recyclerView: RecyclerView) { - super.onAttachedToRecyclerView(recyclerView) - job = Job() - } - - override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) { - super.onDetachedFromRecyclerView(recyclerView) - job.cancel() - } } diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlAdapter.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlAdapter.kt index b7891dc71..05c20ce6a 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlAdapter.kt @@ -11,10 +11,8 @@ import androidx.annotation.DrawableRes import androidx.annotation.LayoutRes import androidx.annotation.StringRes import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import io.reactivex.Observer -import kotlinx.coroutines.Job import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionHeaderViewHolder import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionViewHolder import org.mozilla.fenix.home.sessioncontrol.viewholders.NoContentMessageViewHolder @@ -31,6 +29,7 @@ import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingPr import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingSectionHeaderViewHolder import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingThemePickerViewHolder import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingTrackingProtectionViewHolder +import org.mozilla.fenix.utils.ListAdapterWithJob import mozilla.components.feature.tab.collections.Tab as ComponentTab sealed class AdapterItem(@LayoutRes val viewType: Int) { @@ -92,9 +91,7 @@ class AdapterItemDiffCallback : DiffUtil.ItemCallback() { class SessionControlAdapter( private val actionEmitter: Observer -) : ListAdapter(AdapterItemDiffCallback()) { - - private lateinit var job: Job +) : ListAdapterWithJob(AdapterItemDiffCallback()) { // This method triggers the ComplexMethod lint error when in fact it's quite simple. @SuppressWarnings("ComplexMethod") @@ -102,13 +99,13 @@ class SessionControlAdapter( val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false) return when (viewType) { TabHeaderViewHolder.LAYOUT_ID -> TabHeaderViewHolder(view, actionEmitter) - TabViewHolder.LAYOUT_ID -> TabViewHolder(view, actionEmitter, job) + TabViewHolder.LAYOUT_ID -> TabViewHolder(view, actionEmitter, adapterJob) SaveTabGroupViewHolder.LAYOUT_ID -> SaveTabGroupViewHolder(view, actionEmitter) PrivateBrowsingDescriptionViewHolder.LAYOUT_ID -> PrivateBrowsingDescriptionViewHolder(view, actionEmitter) NoContentMessageViewHolder.LAYOUT_ID -> NoContentMessageViewHolder(view) CollectionHeaderViewHolder.LAYOUT_ID -> CollectionHeaderViewHolder(view) - CollectionViewHolder.LAYOUT_ID -> CollectionViewHolder(view, actionEmitter, job) - TabInCollectionViewHolder.LAYOUT_ID -> TabInCollectionViewHolder(view, actionEmitter, job) + CollectionViewHolder.LAYOUT_ID -> CollectionViewHolder(view, actionEmitter, adapterJob) + TabInCollectionViewHolder.LAYOUT_ID -> TabInCollectionViewHolder(view, actionEmitter, adapterJob) OnboardingHeaderViewHolder.LAYOUT_ID -> OnboardingHeaderViewHolder(view) OnboardingSectionHeaderViewHolder.LAYOUT_ID -> OnboardingSectionHeaderViewHolder(view) OnboardingFirefoxAccountViewHolder.LAYOUT_ID -> OnboardingFirefoxAccountViewHolder(view) @@ -121,16 +118,6 @@ class SessionControlAdapter( } } - override fun onAttachedToRecyclerView(recyclerView: RecyclerView) { - super.onAttachedToRecyclerView(recyclerView) - job = Job() - } - - override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) { - super.onDetachedFromRecyclerView(recyclerView) - job.cancel() - } - override fun getItemViewType(position: Int) = getItem(position).viewType override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkAdapter.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkAdapter.kt index c308f6f7e..beed60065 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkAdapter.kt @@ -26,10 +26,11 @@ import org.mozilla.fenix.R import org.mozilla.fenix.ThemeManager import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.increaseTapArea +import org.mozilla.fenix.utils.AdapterWithJob import kotlin.coroutines.CoroutineContext class BookmarkAdapter(val emptyView: View, val actionEmitter: Observer) : - RecyclerView.Adapter() { + AdapterWithJob() { private var tree: List = listOf() private var mode: BookmarkState.Mode = BookmarkState.Mode.Normal @@ -37,8 +38,6 @@ class BookmarkAdapter(val emptyView: View, val actionEmitter: Observer BookmarkItemViewHolder( - view, actionEmitter, job + view, actionEmitter, adapterJob ) BookmarkFolderViewHolder.viewType.ordinal -> BookmarkFolderViewHolder( - view, actionEmitter, job + view, actionEmitter, adapterJob ) BookmarkSeparatorViewHolder.viewType.ordinal -> BookmarkSeparatorViewHolder( - view, actionEmitter, job + view, actionEmitter, adapterJob ) else -> throw IllegalStateException("ViewType $viewType does not match to a ViewHolder") } @@ -75,16 +74,6 @@ class BookmarkAdapter(val emptyView: View, val actionEmitter: Observer) { class HistoryAdapter( private val actionEmitter: Observer -) : RecyclerView.Adapter() { +) : AdapterWithJob() { private var historyList: HistoryList = HistoryList(emptyList()) private var mode: HistoryState.Mode = HistoryState.Mode.Normal - private lateinit var job: Job var selected = listOf() fun updateData(items: List, mode: HistoryState.Mode) { @@ -126,7 +124,7 @@ class HistoryAdapter( return when (viewType) { HistoryDeleteButtonViewHolder.LAYOUT_ID -> HistoryDeleteButtonViewHolder(view, actionEmitter) HistoryHeaderViewHolder.LAYOUT_ID -> HistoryHeaderViewHolder(view) - HistoryListItemViewHolder.LAYOUT_ID -> HistoryListItemViewHolder(view, actionEmitter, job) + HistoryListItemViewHolder.LAYOUT_ID -> HistoryListItemViewHolder(view, actionEmitter, adapterJob) else -> throw IllegalStateException() } } @@ -144,14 +142,4 @@ class HistoryAdapter( } } } - - override fun onAttachedToRecyclerView(recyclerView: RecyclerView) { - super.onAttachedToRecyclerView(recyclerView) - job = Job() - } - - override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) { - super.onDetachedFromRecyclerView(recyclerView) - job.cancel() - } } diff --git a/app/src/main/java/org/mozilla/fenix/share/AppShareView.kt b/app/src/main/java/org/mozilla/fenix/share/AppShareView.kt index 3a260540c..9e95e5d60 100644 --- a/app/src/main/java/org/mozilla/fenix/share/AppShareView.kt +++ b/app/src/main/java/org/mozilla/fenix/share/AppShareView.kt @@ -19,10 +19,10 @@ import io.reactivex.Observer import kotlinx.android.synthetic.main.app_share_list_item.view.* import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.mozilla.fenix.R +import org.mozilla.fenix.utils.AdapterWithJob import kotlin.coroutines.CoroutineContext class AppShareRecyclerView @JvmOverloads constructor( @@ -40,11 +40,10 @@ class AppShareAdapter( private val context: Context, val actionEmitter: Observer, private val intentType: String = "text/plain" -) : RecyclerView.Adapter(), CoroutineScope { +) : AdapterWithJob(), CoroutineScope { - private var job: Job = Job() override val coroutineContext: CoroutineContext - get() = Dispatchers.IO + job + get() = Dispatchers.IO + adapterJob private var size: Int = 0 private val shareItems: MutableList = mutableListOf() @@ -87,16 +86,6 @@ class AppShareAdapter( override fun onBindViewHolder(holder: AppShareItemViewHolder, position: Int) { holder.bind(shareItems[position]) } - - override fun onAttachedToRecyclerView(recyclerView: RecyclerView) { - super.onAttachedToRecyclerView(recyclerView) - job = Job() - } - - override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) { - super.onDetachedFromRecyclerView(recyclerView) - job.cancel() - } } class AppShareItemViewHolder( diff --git a/app/src/main/java/org/mozilla/fenix/utils/AdapterWithJob.kt b/app/src/main/java/org/mozilla/fenix/utils/AdapterWithJob.kt new file mode 100644 index 000000000..6417ade33 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/utils/AdapterWithJob.kt @@ -0,0 +1,48 @@ +package org.mozilla.fenix.utils + +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import kotlinx.coroutines.Job + +/* This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * [RecyclerView.Adapter] with a [Job] for coroutines. + * The adapterJob is setup when the adapter is attached to a RecyclerView and canceled when detached. + */ +abstract class AdapterWithJob : RecyclerView.Adapter() { + protected lateinit var adapterJob: Job + + override fun onAttachedToRecyclerView(recyclerView: RecyclerView) { + super.onAttachedToRecyclerView(recyclerView) + adapterJob = Job() + } + + override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) { + super.onDetachedFromRecyclerView(recyclerView) + adapterJob.cancel() + } +} + +/** + * [ListAdapter] with a [Job] for coroutines. + * The adapterJob is setup when the adapter is attached to a RecyclerView and canceled when detached. + */ +abstract class ListAdapterWithJob( + diffCallback: DiffUtil.ItemCallback +) : ListAdapter(diffCallback) { + protected lateinit var adapterJob: Job + + override fun onAttachedToRecyclerView(recyclerView: RecyclerView) { + super.onAttachedToRecyclerView(recyclerView) + adapterJob = Job() + } + + override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) { + super.onDetachedFromRecyclerView(recyclerView) + adapterJob.cancel() + } +}