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