1 /* 2 * Copyright 2021 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 package androidx.lifecycle.viewmodel 17 18 import androidx.lifecycle.ViewModelProvider 19 import androidx.lifecycle.ViewModelProvider.Factory 20 import androidx.lifecycle.viewmodel.CreationExtras.Key 21 import kotlin.jvm.JvmOverloads 22 import kotlin.jvm.JvmStatic 23 24 /** 25 * A map-like object holding pairs of [CreationExtras.Key] and [Any], enabling efficient value 26 * retrieval for each key. Each key in [CreationExtras] is unique, storing only one value per key. 27 * 28 * [CreationExtras] is used in [ViewModelProvider.Factory.create] to provide extra information to 29 * the [Factory]. This makes [Factory] implementations stateless, simplifying factory injection by 30 * not requiring all information at construction time. 31 * 32 * This abstract class supports read-only access; use [MutableCreationExtras] for read-write access. 33 */ 34 public abstract class CreationExtras internal constructor() { 35 internal val extras: MutableMap<Key<*>, Any?> = mutableMapOf() 36 37 /** 38 * Key for the elements of [CreationExtras]. [T] represents the type of element associated with 39 * this key. 40 */ 41 public interface Key<T> 42 43 /** 44 * Returns the value to which the specified [key] is associated, or null if this 45 * [CreationExtras] contains no mapping for the key. 46 */ getnull47 public abstract operator fun <T> get(key: Key<T>): T? 48 49 /** Compares the specified object with this [CreationExtras] for equality. */ 50 override fun equals(other: Any?): Boolean = other is CreationExtras && extras == other.extras 51 52 /** Returns the hash code value for this [CreationExtras]. */ 53 override fun hashCode(): Int = extras.hashCode() 54 55 /** 56 * Returns a string representation of this [CreationExtras]. The string representation consists 57 * of a list of key-value mappings in the order returned by the [CreationExtras]'s iterator. 58 */ 59 override fun toString(): String = "CreationExtras(extras=$extras)" 60 61 /** An empty read-only [CreationExtras]. */ 62 public object Empty : CreationExtras() { 63 override fun <T> get(key: Key<T>): T? = null 64 } 65 66 public companion object { 67 /** Returns an unique [Key] to be associated with an extra. */ Keynull68 @JvmStatic public inline fun <reified T> Key(): Key<T> = object : Key<T> {} 69 } 70 } 71 72 /** 73 * A modifiable [CreationExtras] that holds pairs of [CreationExtras.Key] and [Any], allowing 74 * efficient value retrieval for each key. 75 * 76 * Each key in [CreationExtras] is unique, storing only one value per key. 77 * 78 * @see [CreationExtras] 79 */ 80 public class MutableCreationExtras 81 /** 82 * Constructs a [MutableCreationExtras] containing the elements of the specified `initialExtras`, in 83 * the order they are returned by the [Map]'s iterator. 84 */ 85 internal constructor(initialExtras: Map<Key<*>, Any?>) : CreationExtras() { 86 87 /** 88 * Constructs a [MutableCreationExtras] containing the elements of the specified 89 * [initialExtras], in the order they are returned by the [CreationExtras]'s iterator. 90 */ 91 @JvmOverloads 92 public constructor(initialExtras: CreationExtras = Empty) : this(initialExtras.extras) 93 94 init { 95 extras += initialExtras 96 } 97 98 /** Associates the specified [t] with the specified [key] in this [CreationExtras]. */ setnull99 public operator fun <T> set(key: Key<T>, t: T) { 100 extras[key] = t 101 } 102 103 /** 104 * Returns the value to which the specified [key] is associated, or null if this 105 * [CreationExtras] contains no mapping for the key. 106 */ getnull107 @Suppress("UNCHECKED_CAST") public override fun <T> get(key: Key<T>): T? = extras[key] as T? 108 } 109 110 /** 111 * Checks if the [CreationExtras] contains the given [key]. 112 * 113 * This method allows to use the `key in creationExtras` syntax for checking whether an [key] is 114 * contained in the [CreationExtras]. 115 */ 116 public operator fun CreationExtras.contains(key: Key<*>): Boolean = key in extras 117 118 /** 119 * Creates a new read-only [CreationExtras] by replacing or adding entries to [this] extras from 120 * another [creationExtras]. 121 * 122 * The returned [CreationExtras] preserves the entry iteration order of the original 123 * [CreationExtras]. 124 * 125 * Those entries of another [creationExtras] that are missing in [this] extras are iterated in the 126 * end in the order of that [creationExtras]. 127 */ 128 public operator fun CreationExtras.plus(creationExtras: CreationExtras): MutableCreationExtras = 129 MutableCreationExtras(initialExtras = extras + creationExtras.extras) 130 131 /** Appends or replaces all entries from the given [creationExtras] in [this] mutable extras. */ 132 public operator fun MutableCreationExtras.plusAssign(creationExtras: CreationExtras) { 133 extras += creationExtras.extras 134 } 135