Home | History | Annotate | Download | only in widget
      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 android.os.Handler;
     20 import android.os.Looper;
     21 
     22 import androidx.annotation.NonNull;
     23 import androidx.annotation.RestrictTo;
     24 
     25 import java.util.concurrent.Executor;
     26 import java.util.concurrent.Executors;
     27 
     28 /**
     29  * Configuration object for {@link ListAdapter}, {@link AsyncListDiffer}, and similar
     30  * background-thread list diffing adapter logic.
     31  * <p>
     32  * At minimum, defines item diffing behavior with a {@link DiffUtil.ItemCallback}, used to compute
     33  * item differences to pass to a RecyclerView adapter.
     34  *
     35  * @param <T> Type of items in the lists, and being compared.
     36  */
     37 public final class AsyncDifferConfig<T> {
     38     @NonNull
     39     private final Executor mMainThreadExecutor;
     40     @NonNull
     41     private final Executor mBackgroundThreadExecutor;
     42     @NonNull
     43     private final DiffUtil.ItemCallback<T> mDiffCallback;
     44 
     45     private AsyncDifferConfig(
     46             @NonNull Executor mainThreadExecutor,
     47             @NonNull Executor backgroundThreadExecutor,
     48             @NonNull DiffUtil.ItemCallback<T> diffCallback) {
     49         mMainThreadExecutor = mainThreadExecutor;
     50         mBackgroundThreadExecutor = backgroundThreadExecutor;
     51         mDiffCallback = diffCallback;
     52     }
     53 
     54     /** @hide */
     55     @SuppressWarnings("WeakerAccess")
     56     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     57     @NonNull
     58     public Executor getMainThreadExecutor() {
     59         return mMainThreadExecutor;
     60     }
     61 
     62     @SuppressWarnings("WeakerAccess")
     63     @NonNull
     64     public Executor getBackgroundThreadExecutor() {
     65         return mBackgroundThreadExecutor;
     66     }
     67 
     68     @SuppressWarnings("WeakerAccess")
     69     @NonNull
     70     public DiffUtil.ItemCallback<T> getDiffCallback() {
     71         return mDiffCallback;
     72     }
     73 
     74     /**
     75      * Builder class for {@link AsyncDifferConfig}.
     76      *
     77      * @param <T>
     78      */
     79     public static final class Builder<T> {
     80         private Executor mMainThreadExecutor;
     81         private Executor mBackgroundThreadExecutor;
     82         private final DiffUtil.ItemCallback<T> mDiffCallback;
     83 
     84         public Builder(@NonNull DiffUtil.ItemCallback<T> diffCallback) {
     85             mDiffCallback = diffCallback;
     86         }
     87 
     88         /**
     89          * If provided, defines the main thread executor used to dispatch adapter update
     90          * notifications on the main thread.
     91          * <p>
     92          * If not provided, it will default to the main thread.
     93          *
     94          * @param executor The executor which can run tasks in the UI thread.
     95          * @return this
     96          *
     97          * @hide
     98          */
     99         @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    100         @NonNull
    101         public Builder<T> setMainThreadExecutor(Executor executor) {
    102             mMainThreadExecutor = executor;
    103             return this;
    104         }
    105 
    106         /**
    107          * If provided, defines the background executor used to calculate the diff between an old
    108          * and a new list.
    109          * <p>
    110          * If not provided, defaults to two thread pool executor, shared by all ListAdapterConfigs.
    111          *
    112          * @param executor The background executor to run list diffing.
    113          * @return this
    114          */
    115         @SuppressWarnings({"unused", "WeakerAccess"})
    116         @NonNull
    117         public Builder<T> setBackgroundThreadExecutor(Executor executor) {
    118             mBackgroundThreadExecutor = executor;
    119             return this;
    120         }
    121 
    122         private static class MainThreadExecutor implements Executor {
    123             final Handler mHandler = new Handler(Looper.getMainLooper());
    124             @Override
    125             public void execute(@NonNull Runnable command) {
    126                 mHandler.post(command);
    127             }
    128         }
    129 
    130         /**
    131          * Creates a {@link AsyncListDiffer} with the given parameters.
    132          *
    133          * @return A new AsyncDifferConfig.
    134          */
    135         @NonNull
    136         public AsyncDifferConfig<T> build() {
    137             if (mMainThreadExecutor == null) {
    138                 mMainThreadExecutor = sMainThreadExecutor;
    139             }
    140             if (mBackgroundThreadExecutor == null) {
    141                 synchronized (sExecutorLock) {
    142                     if (sDiffExecutor == null) {
    143                         sDiffExecutor = Executors.newFixedThreadPool(2);
    144                     }
    145                 }
    146                 mBackgroundThreadExecutor = sDiffExecutor;
    147             }
    148             return new AsyncDifferConfig<>(
    149                     mMainThreadExecutor,
    150                     mBackgroundThreadExecutor,
    151                     mDiffCallback);
    152         }
    153 
    154         // TODO: remove the below once supportlib has its own appropriate executors
    155         private static final Object sExecutorLock = new Object();
    156         private static Executor sDiffExecutor = null;
    157 
    158         // TODO: use MainThreadExecutor from supportlib once one exists
    159         private static final Executor sMainThreadExecutor = new MainThreadExecutor();
    160     }
    161 }
    162