1 /*
2  * Copyright 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.recyclerview.widget;
18 
19 import androidx.annotation.RestrictTo;
20 
21 import org.jspecify.annotations.NonNull;
22 import org.jspecify.annotations.Nullable;
23 
24 import java.util.concurrent.Executor;
25 import java.util.concurrent.Executors;
26 
27 /**
28  * Configuration object for {@link ListAdapter}, {@link AsyncListDiffer}, and similar
29  * background-thread list diffing adapter logic.
30  * <p>
31  * At minimum, defines item diffing behavior with a {@link DiffUtil.ItemCallback}, used to compute
32  * item differences to pass to a RecyclerView adapter.
33  *
34  * @param <T> Type of items in the lists, and being compared.
35  */
36 public final class AsyncDifferConfig<T> {
37     private final @Nullable Executor mMainThreadExecutor;
38     private final @NonNull Executor mBackgroundThreadExecutor;
39     private final DiffUtil.@NonNull ItemCallback<T> mDiffCallback;
40 
41     @SuppressWarnings("WeakerAccess") /* synthetic access */
AsyncDifferConfig( @ullable Executor mainThreadExecutor, @NonNull Executor backgroundThreadExecutor, DiffUtil.@NonNull ItemCallback<T> diffCallback)42     AsyncDifferConfig(
43             @Nullable Executor mainThreadExecutor,
44             @NonNull Executor backgroundThreadExecutor,
45             DiffUtil.@NonNull ItemCallback<T> diffCallback) {
46         mMainThreadExecutor = mainThreadExecutor;
47         mBackgroundThreadExecutor = backgroundThreadExecutor;
48         mDiffCallback = diffCallback;
49     }
50 
51     @SuppressWarnings("WeakerAccess")
52     @RestrictTo(RestrictTo.Scope.LIBRARY)
getMainThreadExecutor()53     public @Nullable Executor getMainThreadExecutor() {
54         return mMainThreadExecutor;
55     }
56 
57     @SuppressWarnings("WeakerAccess")
getBackgroundThreadExecutor()58     public @NonNull Executor getBackgroundThreadExecutor() {
59         return mBackgroundThreadExecutor;
60     }
61 
62     @SuppressWarnings("WeakerAccess")
getDiffCallback()63     public DiffUtil.@NonNull ItemCallback<T> getDiffCallback() {
64         return mDiffCallback;
65     }
66 
67     /**
68      * Builder class for {@link AsyncDifferConfig}.
69      *
70      * @param <T>
71      */
72     public static final class Builder<T> {
73         private @Nullable Executor mMainThreadExecutor;
74         private Executor mBackgroundThreadExecutor;
75         private final DiffUtil.ItemCallback<T> mDiffCallback;
76 
Builder(DiffUtil.@onNull ItemCallback<T> diffCallback)77         public Builder(DiffUtil.@NonNull ItemCallback<T> diffCallback) {
78             mDiffCallback = diffCallback;
79         }
80 
81         /**
82          * If provided, defines the main thread executor used to dispatch adapter update
83          * notifications on the main thread.
84          * <p>
85          * If not provided or null, it will default to the main thread.
86          *
87          * @param executor The executor which can run tasks in the UI thread.
88          * @return this
89          *
90          */
91         @RestrictTo(RestrictTo.Scope.LIBRARY)
setMainThreadExecutor(@ullable Executor executor)92         public @NonNull Builder<T> setMainThreadExecutor(@Nullable Executor executor) {
93             mMainThreadExecutor = executor;
94             return this;
95         }
96 
97         /**
98          * If provided, defines the background executor used to calculate the diff between an old
99          * and a new list.
100          * <p>
101          * If not provided or null, defaults to two thread pool executor, shared by all
102          * ListAdapterConfigs.
103          *
104          * @param executor The background executor to run list diffing.
105          * @return this
106          */
107         @SuppressWarnings({"unused", "WeakerAccess"})
setBackgroundThreadExecutor(@ullable Executor executor)108         public @NonNull Builder<T> setBackgroundThreadExecutor(@Nullable Executor executor) {
109             mBackgroundThreadExecutor = executor;
110             return this;
111         }
112 
113         /**
114          * Creates a {@link AsyncListDiffer} with the given parameters.
115          *
116          * @return A new AsyncDifferConfig.
117          */
build()118         public @NonNull AsyncDifferConfig<T> build() {
119             if (mBackgroundThreadExecutor == null) {
120                 synchronized (sExecutorLock) {
121                     if (sDiffExecutor == null) {
122                         sDiffExecutor = Executors.newFixedThreadPool(2);
123                     }
124                 }
125                 mBackgroundThreadExecutor = sDiffExecutor;
126             }
127             return new AsyncDifferConfig<>(
128                     mMainThreadExecutor,
129                     mBackgroundThreadExecutor,
130                     mDiffCallback);
131         }
132 
133         // TODO: remove the below once supportlib has its own appropriate executors
134         private static final Object sExecutorLock = new Object();
135         private static Executor sDiffExecutor = null;
136     }
137 }
138