• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.android.car.arch.common;
18 
19 import static java.util.Objects.requireNonNull;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 
24 import androidx.arch.core.util.Function;
25 import androidx.core.util.Pair;
26 import androidx.lifecycle.LiveData;
27 import androidx.lifecycle.MediatorLiveData;
28 import androidx.lifecycle.MutableLiveData;
29 import androidx.lifecycle.Observer;
30 import androidx.lifecycle.Transformations;
31 
32 import java.util.Objects;
33 import java.util.function.BiConsumer;
34 import java.util.function.BiFunction;
35 import java.util.function.BiPredicate;
36 import java.util.function.Predicate;
37 
38 /**
39  * Utility methods for using {@link LiveData}. In general for Boolean operations, {@code null} is
40  * treated as an "unknown" value, and operations may use short-circuit evaluation to determine the
41  * result. LiveData may be in an uninitialized state where observers are not called when registered
42  * (e.g. a {@link MutableLiveData} where {@link MutableLiveData#setValue(Object)} has not yet been
43  * called). If a Boolean operation receives an uninitialized LiveData as either of its parameters,
44  * the result will also be in an uninitialized state.
45  */
46 @SuppressWarnings({"unused", "WeakerAccess"})
47 public class LiveDataFunctions {
48 
LiveDataFunctions()49     private LiveDataFunctions() {
50     }
51 
52     private static volatile LiveData<?> sNullLiveData;
53     private static volatile LiveData<Boolean> sTrueLiveData;
54     private static volatile LiveData<Boolean> sFalseLiveData;
55 
56     /**
57      * Returns a LiveData that always emits {@code null}. This is different than an uninitialized
58      * LiveData in that observers will be called (with {@code null}) when registered.
59      */
nullLiveData()60     public static <T> LiveData<T> nullLiveData() {
61         if (sNullLiveData == null) {
62             sNullLiveData = dataOf(null);
63         }
64         // null can fit any generic type
65         // noinspection unchecked
66         return (LiveData<T>) sNullLiveData;
67     }
68 
69     /** Returns a LiveData that always emits {@code true}. */
trueLiveData()70     public static LiveData<Boolean> trueLiveData() {
71         if (sTrueLiveData == null) {
72             sTrueLiveData = dataOf(true);
73         }
74         return sTrueLiveData;
75     }
76 
77     /** Returns a LiveData that always emits {@code false}. */
falseLiveData()78     public static LiveData<Boolean> falseLiveData() {
79         if (sFalseLiveData == null) {
80             sFalseLiveData = dataOf(false);
81         }
82         return sFalseLiveData;
83     }
84 
85     /** Returns a LiveData that is initialized with {@code value}. */
dataOf(@ullable T value)86     public static <T> MutableLiveData<T> dataOf(@Nullable T value) {
87         MutableLiveData<T> data = new MutableLiveData<>();
88         data.setValue(value);
89         return data;
90     }
91 
92     /**
93      * Returns a LiveData that emits the opposite of {@code source} (or {@code null} if {@code
94      * source} emits {@code null})
95      */
not(@onNull LiveData<Boolean> source)96     public static LiveData<Boolean> not(@NonNull LiveData<Boolean> source) {
97         return Transformations.map(source, bool -> bool == null ? null : !bool);
98     }
99 
100     /**
101      * Returns a LiveData that emits {@code true} iff {@code source} emits {@code null}. Otherwise
102      * emits {@code false}
103      */
emitsNull(@onNull LiveData<?> source)104     public static LiveData<Boolean> emitsNull(@NonNull LiveData<?> source) {
105         return Transformations.map(source, Objects::isNull);
106     }
107 
108     /**
109      * Returns a LiveData that emits the same value as {@code source}, but only notifies its
110      * observers when the new value is distinct ({@link Objects#equals(Object, Object)}
111      */
distinct(@onNull LiveData<T> source)112     public static <T> LiveData<T> distinct(@NonNull LiveData<T> source) {
113         return distinct(source, Objects::equals);
114     }
115 
116     /**
117      * Returns a LiveData that emits the same value as {@code source}, but only notifies its
118      * observers when the new value is distinct ({@code areEqual} returns {@code false})
119      */
distinct(@onNull LiveData<T> source, @NonNull BiPredicate<T, T> areEqual)120     public static <T> LiveData<T> distinct(@NonNull LiveData<T> source,
121             @NonNull BiPredicate<T, T> areEqual) {
122         return new MediatorLiveData<T>() {
123             private boolean mInitialized = false;
124 
125             {
126                 addSource(source, value -> {
127                     if (!mInitialized || !areEqual.test(value, getValue())) {
128                         mInitialized = true;
129                         setValue(value);
130                     }
131                 });
132             }
133         };
134     }
135 
136     /**
137      * Create a LiveData that doesn't change when {@code isFrozen} emits {@code true}. If {@code
138      * source} has updated while the data was frozen, it will be updated to the current value once
139      * unfrozen.
140      *
141      * @param isFrozen the result will not update while this data emits {@code true}.
142      * @param source   the source data for the result.
143      * @return a LiveData that doesn't change when {@code isFrozen} emits {@code true}.
144      */
freezable(@onNull LiveData<Boolean> isFrozen, @NonNull LiveData<T> source)145     public static <T> LiveData<T> freezable(@NonNull LiveData<Boolean> isFrozen,
146             @NonNull LiveData<T> source) {
147         return new MediatorLiveData<T>() {
148 
149             private boolean mDirty = false;
150 
151             {
152                 addSource(requireNonNull(isFrozen), frozen -> {
153                     if (frozen == Boolean.FALSE && mDirty) {
154                         setValue(source.getValue());
155                         mDirty = false;
156                     }
157                 });
158                 addSource(requireNonNull(source), value -> {
159                     if (isFrozen.getValue() != Boolean.FALSE) {
160                         mDirty = true;
161                     } else {
162                         setValue(source.getValue());
163                         mDirty = false;
164                     }
165                 });
166             }
167         };
168     }
169 
170     /**
171      * Similar to {@link Transformations#map(LiveData, Function)}, but emits {@code null} when
172      * {@code source} emits {@code null}. The input to {@code func} may be treated as not nullable.
173      */
174     public static <T, R> LiveData<R> mapNonNull(@NonNull LiveData<T> source,
175             @NonNull Function<T, R> func) {
176         return mapNonNull(source, null, func);
177     }
178 
179     /**
180      * Similar to {@link Transformations#map(LiveData, Function)}, but emits {@code nullValue} when
181      * {@code source} emits {@code null}. The input to {@code func} may be treated as not nullable.
182      */
183     public static <T, R> LiveData<R> mapNonNull(@NonNull LiveData<T> source, @Nullable R nullValue,
184             @NonNull Function<T, R> func) {
185         return Transformations.map(source, value -> value == null ? nullValue : func.apply(value));
186     }
187 
188     /**
189      * Similar to {@link Transformations#switchMap(LiveData, Function)}, but emits {@code null} when
190      * {@code source} emits {@code null}. The input to {@code func} may be treated as not nullable.
191      */
192     public static <T, R> LiveData<R> switchMapNonNull(@NonNull LiveData<T> source,
193             @NonNull Function<T, LiveData<R>> func) {
194         return switchMapNonNull(source, null, func);
195     }
196 
197     /**
198      * Similar to {@link Transformations#switchMap(LiveData, Function)}, but emits {@code nullValue}
199      * when {@code source} emits {@code null}. The input to {@code func} may be treated as not
200      * nullable.
201      */
202     public static <T, R> LiveData<R> switchMapNonNull(@NonNull LiveData<T> source,
203             @Nullable R nullValue,
204             @NonNull Function<T, LiveData<R>> func) {
205         return Transformations.switchMap(source,
206                 value -> value == null ? nullLiveData() : func.apply(value));
207     }
208 
209     /**
210      * Similar to {@link Transformations#switchMap(LiveData, Function)}, but emits a FutureData,
211      * which provides a loading field for operations which may take a long time to finish.
212      *
213      * This LiveData emits values only when the loading status of the output changes. It will never
214      * emit {@code null}. If the output is loading, the emitted FutureData will have a null value
215      * for the data.
216      */
217     public static <T, R> LiveData<FutureData<R>> loadingSwitchMap(LiveData<T> trigger,
218             @NonNull Function<T, LiveData<R>> func) {
219         LiveData<R> output = Transformations.switchMap(trigger, func);
220         return new MediatorLiveData<FutureData<R>>() {
221             {
222                 addSource(trigger, data -> setValue(new FutureData<>(true, null)));
223                 addSource(output, data ->
224                         setValue(new FutureData<>(false, output.getValue())));
225             }
226         };
227     }
228 
229     /**
230      * Returns a LiveData that emits the logical AND of the two arguments. Also deals with {@code
231      * null} and uninitalized values as follows:
232      * <table>
233      * <tr>
234      * <th></th>
235      * <th>T</th>
236      * <th>F</th>
237      * <th>N</th>
238      * <th>U</th>
239      * </tr>
240      * <tr>
241      * <th>T</th>
242      * <td>T</td>
243      * <td>F</td>
244      * <td>N</td>
245      * <td>U</td>
246      * </tr>
247      * <tr>
248      * <th>F</th>
249      * <td>F</td>
250      * <td>F</td>
251      * <td>F</td>
252      * <td>U</td>
253      * </tr>
254      * <tr>
255      * <th>N</th>
256      * <td>N</td>
257      * <td>F</td>
258      * <td>N</td>
259      * <td>U</td>
260      * </tr>
261      * <tr>
262      * <th>U</th>
263      * <td>U</td>
264      * <td>U</td>
265      * <td>U</td>
266      * <td>U</td>
267      * </tr>
268      * </table>
269      * <p>
270      * T = {@code true}, F = {@code false}, N = {@code null}, U = uninitialized
271      *
272      * @return a LiveData that emits the logical AND of the two arguments
273      */
274     public static LiveData<Boolean> and(@NonNull LiveData<Boolean> x,
275             @NonNull LiveData<Boolean> y) {
276         return new BinaryOperation<>(
277                 x,
278                 y,
279                 (a, b) -> {
280                     if (a == null) {
281                         if (Boolean.FALSE.equals(b)) {
282                             return false;
283                         }
284                         return null;
285                     }
286                     if (a) {
287                         return b;
288                     }
289                     return false;
290                 });
291     }
292 
293     /**
294      * Returns a LiveData that emits the logical OR of the two arguments. Also deals with {@code
295      * null} and uninitalized values as follows:
296      * <table>
297      * <tr>
298      * <th></th>
299      * <th>T</th>
300      * <th>F</th>
301      * <th>N</th>
302      * <th>U</th>
303      * </tr>
304      * <tr>
305      * <th>T</th>
306      * <td>T</td>
307      * <td>T</td>
308      * <td>T</td>
309      * <td>U</td>
310      * </tr>
311      * <tr>
312      * <th>F</th>
313      * <td>T</td>
314      * <td>F</td>
315      * <td>N</td>
316      * <td>U</td>
317      * </tr>
318      * <tr>
319      * <th>N</th>
320      * <td>T</td>
321      * <td>N</td>
322      * <td>N</td>
323      * <td>U</td>
324      * </tr>
325      * <tr>
326      * <th>U</th>
327      * <td>U</td>
328      * <td>U</td>
329      * <td>U</td>
330      * <td>U</td>
331      * </tr>
332      * </table>
333      * <p>
334      * T = {@code true}, F = {@code false}, N = {@code null}, U = uninitialized
335      *
336      * @return a LiveData that emits the logical OR of the two arguments
337      */
338     public static LiveData<Boolean> or(@NonNull LiveData<Boolean> x, @NonNull LiveData<Boolean> y) {
339         return new BinaryOperation<>(
340                 x,
341                 y,
342                 (a, b) -> {
343                     if (a == null) {
344                         if (Boolean.TRUE.equals(b)) {
345                             return true;
346                         }
347                         return null;
348                     }
349                     if (!a) {
350                         return b;
351                     }
352                     return true;
353                 });
354     }
355 
356     /**
357      * Returns a LiveData backed by {@code value} if and only if predicate emits {@code true}. Emits
358      * {@code null} otherwise.
359      * <p>
360      * This is equivalent to {@code iff(predicate, Boolean::booleanValue, value)}
361      *
362      * @see #iff(LiveData, Predicate, LiveData)
363      */
364     public static <T> LiveData<T> iff(
365             @NonNull LiveData<Boolean> predicate, @NonNull LiveData<T> value) {
366         return iff(predicate, Boolean::booleanValue, value);
367     }
368 
369     /**
370      * Returns a LiveData backed by {@code value} if and only if the trigger emits a value that
371      * causes {@code predicate} to return {@code true}. Emits {@code null} otherwise.
372      */
373     public static <P, T> LiveData<T> iff(
374             @NonNull LiveData<P> trigger,
375             @NonNull Predicate<? super P> predicate,
376             @NonNull LiveData<T> value) {
377         return new BinaryOperation<>(
378                 trigger, value, (p, v) -> p == null || !predicate.test(p) ? null : v);
379     }
380 
381     /**
382      * Returns a LiveData that is backed by {@code trueData} when the predicate emits {@code true},
383      * {@code falseData} when the predicate emits {@code false}, and emits {@code null} when the
384      * predicate emits {@code null}.
385      * <p>
386      * This is equivalent to {@code ifThenElse(predicate, Boolean::booleanValue, trueData,
387      * falseData)}
388      *
389      * @param trueData  the LiveData whose value should be emitted when predicate is {@code true}
390      * @param falseData the LiveData whose value should be emitted when predicate is {@code false}
391      * @see #ifThenElse(LiveData, Predicate, LiveData, LiveData)
392      */
393     public static <T> LiveData<T> ifThenElse(
394             @NonNull LiveData<Boolean> predicate,
395             @NonNull LiveData<T> trueData,
396             @NonNull LiveData<T> falseData) {
397         return ifThenElse(predicate, Boolean::booleanValue, trueData, falseData);
398     }
399 
400     /**
401      * Returns a LiveData that is backed by {@code trueData} when the trigger satisfies the
402      * predicate, {@code falseData} when the trigger does not satisfy the predicate, and emits
403      * {@code null} when the trigger emits {@code null}.
404      *
405      * @param trueData  the LiveData whose value should be emitted when predicate returns {@code
406      *                  true}
407      * @param falseData the LiveData whose value should be emitted when predicate returns {@code
408      *                  false}
409      */
410     public static <P, T> LiveData<T> ifThenElse(
411             @NonNull LiveData<P> trigger,
412             @NonNull Predicate<? super P> predicate,
413             @NonNull LiveData<T> trueData,
414             @NonNull LiveData<T> falseData) {
415         return Transformations.switchMap(
416                 trigger,
417                 t -> {
418                     if (t == null) {
419                         return nullLiveData();
420                     } else {
421                         return predicate.test(t) ? trueData : falseData;
422                     }
423                 });
424     }
425 
426     /**
427      * Returns a LiveData that emits {@code trueValue} when the predicate emits {@code true}, {@code
428      * falseValue} when the predicate emits {@code false}, and emits {@code null} when the predicate
429      * emits {@code null}.
430      * <p>
431      * This is equivalent to {@code ifThenElse(predicate, Boolean::booleanValue, trueValue,
432      * falseValue)}
433      *
434      * @param trueValue  the value that should be emitted when predicate returns {@code true}
435      * @param falseValue the value that should be emitted when predicate returns {@code false}
436      * @see #ifThenElse(LiveData, Predicate, Object, Object)
437      */
438     public static <T> LiveData<T> ifThenElse(
439             @NonNull LiveData<Boolean> predicate, @Nullable T trueValue, @Nullable T falseValue) {
440         return ifThenElse(predicate, Boolean::booleanValue, trueValue, falseValue);
441     }
442 
443     /**
444      * Returns a LiveData that emits {@code trueValue} when the trigger satisfies the predicate,
445      * {@code falseValue} when the trigger does not satisfy the predicate, and emits {@code null}
446      * when the trigger emits {@code null}.
447      *
448      * @param trueValue  the value that should be emitted when predicate returns {@code true}
449      * @param falseValue the value that should be emitted when predicate returns {@code false}
450      */
451     public static <P, T> LiveData<T> ifThenElse(
452             @NonNull LiveData<P> trigger,
453             @NonNull Predicate<? super P> predicate,
454             @Nullable T trueValue,
455             @Nullable T falseValue) {
456         return Transformations.map(
457                 trigger,
458                 t -> {
459                     if (t == null) {
460                         return null;
461                     }
462                     return predicate.test(t) ? trueValue : falseValue;
463                 });
464     }
465 
466     /**
467      * Returns a LiveData that emits the value of {@code source} if it is not {@code null},
468      * otherwise it emits the value of {@code fallback}.
469      *
470      * @param source   The LiveData whose value should be emitted if not {@code null}
471      * @param fallback The LiveData whose value should be emitted when {@code source} emits {@code
472      *                 null}
473      */
474     public static <T> LiveData<T> coalesceNull(@NonNull LiveData<T> source,
475             @NonNull LiveData<T> fallback) {
476         return new BinaryOperation<>(source, fallback, true, false,
477                 (sourceValue, fallbackValue) -> sourceValue == null ? fallbackValue : sourceValue);
478     }
479 
480     /**
481      * Returns a LiveData that emits the value of {@code source} if it is not {@code null},
482      * otherwise it emits {@code fallback}.
483      *
484      * @param source   The LiveData whose value should be emitted if not {@code null}
485      * @param fallback The value that should be emitted when {@code source} emits {@code null}
486      */
487     public static <T> LiveData<T> coalesceNull(@NonNull LiveData<T> source, T fallback) {
488         return Transformations.map(source, value -> value == null ? fallback : value);
489     }
490 
491     /**
492      * Returns a LiveData that emits a Pair containing the values of the two parameter LiveDatas. If
493      * either parameter is uninitialized, the resulting LiveData is also uninitialized.
494      * <p>
495      * This is equivalent to calling {@code combine(tData, uData, Pair::new)}.
496      *
497      * @see #combine(LiveData, LiveData, BiFunction)
498      */
499     public static <T, U> LiveData<Pair<T, U>> pair(
500             @NonNull LiveData<T> tData, @NonNull LiveData<U> uData) {
501         return combine(tData, uData, Pair::new);
502     }
503 
504     /**
505      * Returns an observer that splits a pair into two separate arguments. This method is mainly
506      * used to simplify lambda expressions and enable method references, especially in combination
507      * with {@link #pair(LiveData, LiveData)}.
508      * <p>
509      * Example:
510      * <pre><code>
511      * class MyViewModel extends ViewModel {
512      *   LiveData&lt;Integer> getIntData() {...}
513      *   LiveData&lt;Boolean> getBoolData() {...}
514      * }
515      *
516      * void consume(int intValue, boolean booleanValue) {...}
517      *
518      * void startObserving(MyViewModel viewModel) {
519      *   pair(viewModel.getIntData(), viewModel.getBoolData()).observe(owner, split(this::consume));
520      * }</code></pre>
521      */
522     public static <T, U> Observer<Pair<T, U>> split(@NonNull BiConsumer<T, U> consumer) {
523         return (pair) -> {
524             if (pair == null) {
525                 consumer.accept(null, null);
526             } else {
527                 consumer.accept(pair.first, pair.second);
528             }
529         };
530     }
531 
532     /**
533      * Returns a switch Function that splits a pair into two separate arguments. This method is
534      * mainly used to simplify lambda expressions and enable method references for {@link
535      * Transformations#switchMap(LiveData, Function) switchMaps}, especially in combination with
536      * {@link #pair(LiveData, LiveData)}.
537      */
538     public static <T, U, V> Function<Pair<T, U>, LiveData<V>> split(
539             @NonNull BiFunction<T, U, LiveData<V>> function) {
540         return (pair) -> {
541             if (pair == null) {
542                 return function.apply(null, null);
543             } else {
544                 return function.apply(pair.first, pair.second);
545             }
546         };
547     }
548 
549     /**
550      * Returns a LiveData that emits the result of {@code function} on the values of the two
551      * parameter LiveDatas. If either parameter is uninitialized, the resulting LiveData is also
552      * uninitialized.
553      */
554     public static <T, U, R> LiveData<R> combine(
555             @NonNull LiveData<T> tData,
556             @NonNull LiveData<U> uData,
557             @NonNull BiFunction<T, U, R> function) {
558         return new BinaryOperation<>(tData, uData, function);
559     }
560 
561     private static class BinaryOperation<T, U, R> extends MediatorLiveData<R> {
562         @NonNull
563         private final BiFunction<T, U, R> mFunction;
564 
565         private boolean mTSet;
566         private boolean mUSet;
567         private boolean mValueSet;
568 
569         @Nullable
570         private T mTValue;
571         @Nullable
572         private U mUValue;
573 
574         BinaryOperation(
575                 @NonNull LiveData<T> tLiveData,
576                 @NonNull LiveData<U> uLiveData,
577                 @NonNull BiFunction<T, U, R> function) {
578             this(tLiveData, uLiveData, true, true, function);
579         }
580 
581         BinaryOperation(
582                 @NonNull LiveData<T> tLiveData,
583                 @NonNull LiveData<U> uLiveData,
584                 boolean requireTSet,
585                 boolean requireUSet,
586                 @NonNull BiFunction<T, U, R> function) {
587             this.mFunction = function;
588             if (!requireTSet) {
589                 mTSet = true;
590             }
591             if (!requireUSet) {
592                 mUSet = true;
593             }
594             if (tLiveData == uLiveData) {
595                 // Only add the source once and only update once when it changes.
596                 addSource(
597                         tLiveData,
598                         value -> {
599                             mTSet = true;
600                             mUSet = true;
601                             mTValue = value;
602                             // if both references point to the same LiveData, then T and U are
603                             // compatible types.
604                             // noinspection unchecked
605                             mUValue = (U) value;
606                             update();
607                         });
608             } else {
609                 addSource(requireNonNull(tLiveData), this::updateT);
610                 addSource(requireNonNull(uLiveData), this::updateU);
611             }
612         }
613 
614         private void updateT(@Nullable T tValue) {
615             mTSet = true;
616             this.mTValue = tValue;
617             update();
618         }
619 
620         private void updateU(@Nullable U uValue) {
621             mUSet = true;
622             this.mUValue = uValue;
623             update();
624         }
625 
626         private void update() {
627             if (mTSet && mUSet) {
628                 R result = mFunction.apply(mTValue, mUValue);
629                 // Don't setValue if it's the same as the old value unless we haven't set a value
630                 // before.
631                 if (!mValueSet || result != getValue()) {
632                     mValueSet = true;
633                     setValue(result);
634                 }
635             }
636         }
637     }
638 }
639