<lambda>null1package leakcanary.internal 2 3 import androidx.lifecycle.ViewModel 4 import androidx.lifecycle.ViewModelProvider 5 import androidx.lifecycle.ViewModelProvider.Factory 6 import androidx.lifecycle.ViewModelStore 7 import androidx.lifecycle.ViewModelStoreOwner 8 import leakcanary.ReachabilityWatcher 9 import leakcanary.internal.ViewModelClearedWatcher.Companion.install 10 import shark.SharkLog 11 12 /** 13 * [AndroidXFragmentDestroyWatcher] calls [install] to add a spy [ViewModel] in every 14 * [ViewModelStoreOwner] instance (i.e. FragmentActivity and Fragment). [ViewModelClearedWatcher] 15 * holds on to the map of [ViewModel]s backing its store. When [ViewModelClearedWatcher] receives 16 * the [onCleared] callback, it adds each live [ViewModel] from the store to the [ReachabilityWatcher]. 17 */ 18 internal class ViewModelClearedWatcher( 19 storeOwner: ViewModelStoreOwner, 20 private val reachabilityWatcher: ReachabilityWatcher 21 ) : ViewModel() { 22 23 // We could call ViewModelStore#keys with a package spy in androidx.lifecycle instead, 24 // however that was added in 2.1.0 and we support AndroidX first stable release. viewmodel-2.0.0 25 // does not have ViewModelStore#keys. All versions currently have the mMap field. 26 private val viewModelMap: Map<String, ViewModel>? = try { 27 val storeClass = ViewModelStore::class.java 28 val mapField = try { 29 storeClass.getDeclaredField("map") 30 } catch (exception: NoSuchFieldException) { 31 // Field name changed from mMap to map with Kotlin conversion 32 // https://cs.android.com/androidx/platform/frameworks/support/+/8aa6ca1c924ab10d263b21b99b8790d5f0b50cc6 33 storeClass.getDeclaredField("mMap") 34 } 35 mapField.isAccessible = true 36 @Suppress("UNCHECKED_CAST") 37 mapField[storeOwner.viewModelStore] as Map<String, ViewModel> 38 } catch (ignored: Exception) { 39 SharkLog.d(ignored) { "Could not find ViewModelStore map of view models" } 40 null 41 } 42 43 override fun onCleared() { 44 viewModelMap?.values?.forEach { viewModel -> 45 reachabilityWatcher.expectWeaklyReachable( 46 viewModel, "${viewModel::class.java.name} received ViewModel#onCleared() callback" 47 ) 48 } 49 } 50 51 companion object { 52 fun install( 53 storeOwner: ViewModelStoreOwner, 54 reachabilityWatcher: ReachabilityWatcher 55 ) { 56 val provider = ViewModelProvider(storeOwner, object : Factory { 57 @Suppress("UNCHECKED_CAST") 58 override fun <T : ViewModel?> create(modelClass: Class<T>): T = 59 ViewModelClearedWatcher(storeOwner, reachabilityWatcher) as T 60 }) 61 provider.get(ViewModelClearedWatcher::class.java) 62 } 63 } 64 } 65