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<Integer> getIntData() {...} 513 * LiveData<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