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