Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Service由来のViewでViewModelを使えるようにしてみた

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for yurihondo yurihondo
October 15, 2021

 Service由来のViewでViewModelを使えるようにしてみた

Avatar for yurihondo

yurihondo

October 15, 2021
Tweet

More Decks by yurihondo

Other Decks in Programming

Transcript

  1. p. 2 2021/10/1 5 Doc. Nr: Rev: Public About me

    yurihondo (旧)URI Softwere Engineer@Sony - Game enhancer 試用期間中、二児の父 Twitter : yurihondo @yuyuyuyuyuri About me
  2. p. 3 2021/10/1 5 Doc. Nr: Rev: Public Index •

    Background • Unlock ViewModel • Unlock Dagger Hilt
  3. p. 6 2021/10/1 5 Doc. Nr: Rev: Public How the

    overlay works Serviceから WindowManager経由で WindowへViewを追加
  4. p. 8 2021/10/1 5 Doc. Nr: Rev: Public OverlayしているViewは ActivityやFragmentなどには

    由来せず、完全にServiceに より管理されている。 How the overlay works
  5. p. 13 2021/10/1 5 Doc. Nr: Rev: Public How to

    provide ViewModel 以下のコンポーネントを用いて実現している • ViewModelProvider • ViewModelProvider.Factory • ViewModelStore • ViewModelStoreOwner
  6. p. 17 2021/10/1 5 Doc. Nr: Rev: Public class MyView(

    context: Context, viewModelStoreRepository: ViewModelStoewRepository ) : FrameLayout(context), ViewModelStoreOwner { override fun getViewModelStore(): ViewModelStore { return viewModelStoreRepository.getViewModelStore(this) } override fun onDetachedFromWindow() { viewModelStoreRepository.getViewModelStore(this).clear() } } Implement ViewModelStoreOwner
  7. p. 18 2021/10/1 5 Doc. Nr: Rev: Public class MyView(

    context: Context, viewModelStoreRepository: ViewModelStoewRepository ) : FrameLayout(context), ViewModelStoreOwner { override fun getViewModelStore(): ViewModelStore { return viewModelStoreRepository.getViewModelStore(this) } override fun onDetachedFromWindow() { viewModelStoreRepository.getViewModelStore(this).clear() } } ViewModelStoreOwnerを実装する #getViewModelStoreをOverrideしてViewModelStoreを返す必要がある Implement ViewModelStoreOwner
  8. p. 19 2021/10/1 5 Doc. Nr: Rev: Public class MyView(

    context: Context, viewModelStoreRepository: ViewModelStoewRepository ) : FrameLayout(context), ViewModelStoreOwner { override fun getViewModelStore(): ViewModelStore { return viewModelStoreRepository.getViewModelStore(this) } override fun onDetachedFromWindow() { viewModelStoreRepository.getViewModelStore(this).clear() } } View毎に作成されるViewModelStoreをViewの生存期間とは連動しない形で 管理する必要があるため保存場所を用意する Implement ViewModelStoreOwner
  9. p. 20 2021/10/1 5 Doc. Nr: Rev: Public @Singleton class

    ViewModelStoreRepository { private val viewModelStores: MutableMap<String, ViewModelStore> = Collections.synchronizedMap(mutableMapOf()) fun getViewModelStore(v: View): ViewModelStore { return viewModelStores[who] ?: let { val newStore = ViewModelStore() viewModelStores[ v::class.java.name ] = newStore return@let newStore } } } Implement ViewModelStoreOwner
  10. p. 21 2021/10/1 5 Doc. Nr: Rev: Public @Singleton class

    ViewModelStoreRepository { private val viewModelStores: MutableMap<String, ViewModelStore> = Collections.synchronizedMap(mutableMapOf()) fun getViewModelStore(v: View): ViewModelStore { return viewModelStores[who] ?: let { val newStore = ViewModelStore() viewModelStores[ v::class.java.name ] = newStore return@let newStore } } } View毎にViewModelStoreを 作ってMapで保持している Implement ViewModelStoreOwner
  11. p. 22 2021/10/1 5 Doc. Nr: Rev: Public class MyView(

    context: Context, viewModelStoreRepository: ViewModelStoewRepository ) : FrameLayout(context), ViewModelStoreOwner { override fun getViewModelStore(): ViewModelStore { return viewModelStoreRepository.getViewModelStore(this) } override fun onDetachedFromWindow() { viewModelStoreRepository.getViewModelStore(this).clear() } } ViewModelを維持する必要がなくなった らこのViewModelStoreをクリアする Implement ViewModelStoreOwner
  12. p. 24 2021/10/1 5 Doc. Nr: Rev: Public inline fun

    <reified VM : ViewModel> View.viewModels( noinline ownerProducer: () -> ViewModelStoreOwner = { this as ViewModelStoreOwner }, noinline factoryProducer: (() -> Factory)? = null ): Lazy<VM> = ViewModelLazy( viewModelClass = VM::class, ownerProducer = ownerProducer, factoryProducer = factoryProducer ) ・・・ Property delegateをできるようにしたりして... Implement ViewModelStoreOwner
  13. p. 25 2021/10/1 5 Doc. Nr: Rev: Public class MyView(...)

    : ... { ... private val viewModel by viewModels<MyViewModel>() ... } それっぽくなった Implement ViewModelStoreOwner
  14. p. 27 2021/10/1 5 Doc. Nr: Rev: Public How DI

    container works with Hilt • コンストラクションロジックをModuleに保持 • ComponentといわれるInjectorで依存性を注入 • 注入先はAnnotatoinで指定したEntryPoint
  15. p. 28 2021/10/1 5 Doc. Nr: Rev: Public コンストラクションロジッ ク

    Module class MainActivity:..() { @Inject lateinit var hoge: Hoge … } Component EntryPoint How DI container works with Hilt
  16. p. 29 2021/10/1 5 Doc. Nr: Rev: Public 現在サポートしているのは以下のコンポーネント •

    Application (by using @HiltAndroidApp) • ViewModel (by using @HiltViewModel) • Activity • Fragment • View • Service • BroadcastReceiver How DI container works with Hilt
  17. p. 30 2021/10/1 5 Doc. Nr: Rev: Public How to

    implement Hilt to View @AndroidEntryPoint class MyView : ... { @Inject lateinit var hoge: Hoge ... }
  18. p. 31 2021/10/1 5 Doc. Nr: Rev: Public @AndroidEntryPoint class

    MyView : ... { @Inject lateinit var hoge: Hoge ... } How to implement Hilt to View
  19. p. 32 2021/10/1 5 Doc. Nr: Rev: Public @AndroidEntryPoint class

    MyView : ... { @Inject lateinit var hoge: Hoge ... } ViewはHiltのサポート対象だが、 AcitivityかFragmentから利用されている もの(Contextを共有できているもの) に限る How to implement Hilt to View
  20. p. 33 2021/10/1 5 Doc. Nr: Rev: Public @AndroidEntryPoint class

    MyView : ... { @Inject lateinit var hoge: Hoge ... } Service由来のViewでは @AndroidEntryPointは使えない... How to implement Hilt to View
  21. p. 34 2021/10/1 5 Doc. Nr: Rev: Public class MyView

    (...) : ... { @EntryPoint @InstallIn(SingletonComponent::class) interface MyViewEntryPoint{ fun getHoge(): Hoge } ... } How to implement Hilt to View
  22. p. 35 2021/10/1 5 Doc. Nr: Rev: Public class MyView

    (...) : ... { @EntryPoint @InstallIn(SingletonComponent::class) interface MyViewEntryPoint{ fun getHoge(): Hoge } ... } How to implement Hilt to View EntryPointを定義してインジェクトしてもらう
  23. p. 36 2021/10/1 5 Doc. Nr: Rev: Public class MyView

    (...) : ... { ... private val hoge by lazy { EntryPoints.get(context, MyViewEntryPoint::class.java).getHoge() } ... } How to implement Hilt to View
  24. p. 38 2021/10/1 5 Doc. Nr: Rev: Public @HiltViewModel class

    MyViewModel @Inject constructor( private val fugaRepository: FugaRepository ) : ViewModel() { ... } How to implement Hilt to ViewModel
  25. p. 39 2021/10/1 5 Doc. Nr: Rev: Public @HiltViewModel class

    MyViewModel @Inject constructor( private val fugaRepository: FugaRepository ) : ViewModel() { ... } How to implement Hilt to ViewModel
  26. p. 41 2021/10/1 5 Doc. Nr: Rev: MainActivity HILT_MainActivity Appcompat

    Activity ビルド時にHiltがInject対象のActivityのSuperClassを差し込み 依存関係の解決を実現している How to implement Hilt to ViewModel
  27. p. 42 2021/10/1 5 Doc. Nr: Rev: MainActivity HILT_MainActivity Appcompat

    Activity ビルド時にHiltがInject対象のActivityのSuperClassを差し込み 依存関係の解決を実現している HiltViewModelFactory How to implement Hilt to ViewModel
  28. p. 46 2021/10/1 5 Doc. Nr: Rev: Public HILT_MainActivity HiltViewModelFactory

    How to implement Hilt to ViewModel これが作れれば...!!
  29. p. 47 2021/10/1 5 Doc. Nr: Rev: Public public static

    Factory getActivityFactory( ComponentActivity activity, Factory delegateFactory ) { return ( (DefaultViewModelFactories.ActivityEntryPoint)EntryPoints .get(activity, DefaultViewModelFactories.ActivityEntryPoint.class) ).getHiltInternalFactoryFactory().fromActivity(activity, delegateFactory); } How to implement Hilt to ViewModel
  30. p. 48 2021/10/1 5 Doc. Nr: Rev: Public public static

    Factory getActivityFactory( ComponentActivity activity, Factory delegateFactory ) { return ( (DefaultViewModelFactories.ActivityEntryPoint)EntryPoints .get(activity, DefaultViewModelFactories.ActivityEntryPoint.class) ).getHiltInternalFactoryFactory().fromActivity(activity, delegateFactory); } How to implement Hilt to ViewModel
  31. p. 49 2021/10/1 5 Doc. Nr: Rev: Public public static

    Factory getActivityFactory( ComponentActivity activity, Factory delegateFactory ) { return ( (DefaultViewModelFactories.ActivityEntryPoint)EntryPoints .get(activity, DefaultViewModelFactories.ActivityEntryPoint.class) ).getHiltInternalFactoryFactory().fromActivity(activity, delegateFactory); } ActivityEntryPointを取ってきている How to implement Hilt to ViewModel
  32. p. 50 2021/10/1 5 Doc. Nr: Rev: Public public static

    Factory getActivityFactory( ComponentActivity activity, Factory delegateFactory ) { return ( (DefaultViewModelFactories.ActivityEntryPoint)EntryPoints .get(activity, DefaultViewModelFactories.ActivityEntryPoint.class) ).getHiltInternalFactoryFactory().fromActivity(activity, delegateFactory); } InternalFactoryFactoryを取得 How to implement Hilt to ViewModel
  33. p. 51 2021/10/1 5 Doc. Nr: Rev: Public public static

    Factory getActivityFactory( ComponentActivity activity, Factory delegateFactory ) { return ( (DefaultViewModelFactories.ActivityEntryPoint)EntryPoints .get(activity, DefaultViewModelFactories.ActivityEntryPoint.class) ).getHiltInternalFactoryFactory().fromActivity(activity, delegateFactory); } HiltViewModelFactoryを生成 How to implement Hilt to ViewModel
  34. p. 52 2021/10/1 5 Doc. Nr: Rev: Public public static

    Factory getActivityFactory( ComponentActivity activity, Factory delegateFactory ) { return ( (DefaultViewModelFactories.ActivityEntryPoint)EntryPoints .get(activity, DefaultViewModelFactories.ActivityEntryPoint.class) ).getHiltInternalFactoryFactory().fromActivity(activity, delegateFactory); } 取得は難しそう How to implement Hilt to ViewModel
  35. p. 53 2021/10/1 5 Doc. Nr: Rev: Public public static

    Factory getActivityFactory( ComponentActivity activity, Factory delegateFactory ) { return ( (DefaultViewModelFactories.ActivityEntryPoint)EntryPoints .get(activity, DefaultViewModelFactories.ActivityEntryPoint.class) ).getHiltInternalFactoryFactory().fromActivity(activity, delegateFactory); } これが作れれば... How to implement Hilt to ViewModel
  36. p. 54 2021/10/1 5 Doc. Nr: Rev: Public public static

    Factory getActivityFactory( ComponentActivity activity, Factory delegateFactory ) { return ( (DefaultViewModelFactories.ActivityEntryPoint)EntryPoints .get(activity, DefaultViewModelFactories.ActivityEntryPoint.class) ).getHiltInternalFactoryFactory().fromActivity(activity, delegateFactory); } どうだろ... How to implement Hilt to ViewModel
  37. p. 55 2021/10/1 5 Doc. Nr: Rev: Public Factory fromActivity(

    ComponentActivity activity, Factory delegateFactory ) { return this.getHiltViewModelFactory( activity, activity.getIntent() != null ? activity.getIntent().getExtras() : null, DelegateFactory ); } How to implement Hilt to ViewModel
  38. p. 56 2021/10/1 5 Doc. Nr: Rev: Public Factory fromActivity(

    ComponentActivity activity, Factory delegateFactory ) { return this.getHiltViewModelFactory( activity, activity.getIntent() != null ? activity.getIntent().getExtras() : null, DelegateFactory ); } How to implement Hilt to ViewModel
  39. p. 57 2021/10/1 5 Doc. Nr: Rev: Public private Factory

    getHiltViewModelFactory( SavedStateRegistryOwner owner, @Nullable Bundle defaultArgs, @Nullable Factory extensionDelegate ) { Factory delegate = ... return new HiltViewModelFactory(...); } How to implement Hilt to ViewModel
  40. p. 58 2021/10/1 5 Doc. Nr: Rev: Public private Factory

    getHiltViewModelFactory( SavedStateRegistryOwner owner, @Nullable Bundle defaultArgs, @Nullable Factory extensionDelegate ) { Factory delegate = ... return new HiltViewModelFactory(...); } Activityである必要はない模様 How to implement Hilt to ViewModel
  41. p. 59 2021/10/1 5 Doc. Nr: Rev: Public private Factory

    getHiltViewModelFactory( SavedStateRegistryOwner owner, @Nullable Bundle defaultArgs, @Nullable Factory extensionDelegate ) { Factory delegate = ... return new HiltViewModelFactory(...); } nullでいいはず How to implement Hilt to ViewModel
  42. p. 60 2021/10/1 5 Doc. Nr: Rev: Public private Factory

    getHiltViewModelFactory( SavedStateRegistryOwner owner, @Nullable Bundle defaultArgs, @Nullable Factory extensionDelegate ) { Factory delegate = ... return new HiltViewModelFactory(...); } これも大丈夫そう How to implement Hilt to ViewModel
  43. p. 62 2021/10/1 5 Doc. Nr: Rev: Public @Inject InternalFactoryFactory(

    Application application, @KeySet Set<String> keySet, ViewModelComponentBuilder viewModelComponentBuilder ) { this.application = application; this.keySet = keySet; this.viewModelComponentBuilder = viewModelComponentBuilder; } How to implement Hilt to ViewModel
  44. p. 63 2021/10/1 5 Doc. Nr: Rev: Public @Inject InternalFactoryFactory(

    Application application, @KeySet Set<String> keySet, ViewModelComponentBuilder viewModelComponentBuilder ) { this.application = application; this.keySet = keySet; this.viewModelComponentBuilder = viewModelComponentBuilder; } 問題なさそう How to implement Hilt to ViewModel
  45. p. 64 2021/10/1 5 Doc. Nr: Rev: Public @Inject InternalFactoryFactory(

    Application application, @KeySet Set<String> keySet, ViewModelComponentBuilder viewModelComponentBuilder ) { this.application = application; this.keySet = keySet; this.viewModelComponentBuilder = viewModelComponentBuilder; } なんとか...なるか....? How to implement Hilt to ViewModel
  46. p. 65 2021/10/1 5 Doc. Nr: Rev: Public @Inject InternalFactoryFactory(

    Application application, @KeySet Set<String> keySet, ViewModelComponentBuilder viewModelComponentBuilder ) { this.application = application; this.keySet = keySet; this.viewModelComponentBuilder = viewModelComponentBuilder; } ViewModelComponent...なるほど How to implement Hilt to ViewModel
  47. p. 69 2021/10/1 5 Doc. Nr: Rev: Public class MyViewModelFactory

    @Inject constructor(@ApplicationContext private val context: Context) : ViewModelProvider.Factory { @EntryPoint @InstallIn(SingletonComponent::class) interface MyViewModelFactoryEntryPoint { fun getHoge(): Hoge } override fun <T : ViewModel?> create(modelClass: Class<T>): T { val args = when (modelClass) { MyViewModel::class.java -> { listOf<Any>( EntryPoints.get(context, MyViewModelFactoryEntryPoint::class.java).getHoge() ) } else -> throw RuntimeException(...) } return modelClass.getConstructor(args.map{it::class.java}).newInstance(args) } } How to implement Hilt to ViewModel
  48. p. 70 2021/10/1 5 Doc. Nr: Rev: Public class MyViewModelFactory

    @Inject constructor(@ApplicationContext private val context: Context) : ViewModelProvider.Factory { @EntryPoint @InstallIn(SingletonComponent::class) interface MyViewModelFactoryEntryPoint { fun getHoge(): Hoge } override fun <T : ViewModel?> create(modelClass: Class<T>): T { val args = when (modelClass) { MyViewModel::class.java -> { listOf<Any>( EntryPoints.get(context, MyViewModelFactoryEntryPoint::class.java).getHoge() ) } else -> throw RuntimeException(...) } return modelClass.getConstructor(args.map{it::class.java}).newInstance(args) } } How to implement Hilt to ViewModel
  49. p. 71 2021/10/1 5 Doc. Nr: Rev: Public @EntryPoint @InstallIn(SingletonComponent::class)

    interface MyViewModelFactoryEntryPoint { fun getHoge(): Hoge } How to implement Hilt to ViewModel
  50. p. 72 2021/10/1 5 Doc. Nr: Rev: Public class MyViewModelFactory

    @Inject constructor(@ApplicationContext private val context: Context) : ViewModelProvider.Factory { @EntryPoint @InstallIn(SingletonComponent::class) interface MyViewModelFactoryEntryPoint { fun getHoge(): Hoge } override fun <T : ViewModel?> create(modelClass: Class<T>): T { val args = when (modelClass) { MyViewModel::class.java -> { listOf<Any>( EntryPoints.get(context, MyViewModelFactoryEntryPoint::class.java).getHoge() ) } else -> throw RuntimeException(...) } return modelClass.getConstructor(args.map{it::class.java}).newInstance(args) } } How to implement Hilt to ViewModel
  51. p. 73 2021/10/1 5 Doc. Nr: Rev: Public override fun

    <T : ViewModel?> create(modelClass: Class<T>): T { val args = when (modelClass) { MyViewModel::class.java -> { listOf<Any>( EntryPoints.get(context, MyViewModelFactoryEntryPoint::class.java).getHoge() ) } else -> throw RuntimeException(...) } return modelClass.getConstructor(args.map{it::class.java}).newInstance(args) } How to implement Hilt to ViewModel
  52. p. 74 2021/10/1 5 Doc. Nr: Rev: Public @EntryPoint @InstallIn(SingletonComponent::class)

    interface MyViewEntryPoint{ fun getMyViewModelFactory(): MyViewModelFactory } private val viewModel by viewModels<MyViewModel>{ EntryPoints.get( context.applicationContext, MyViewEntryPoint::class.java ).getMyViewModelFactory() } How to implement Hilt to ViewModel
  53. SONY is a registered trademark of Sony Corporation. Names of

    Sony products and services are the registered trademarks and/or trademarks of Sony Corporation or its Group companies. Other company names and product names are registered trademarks and/or trademarks of the respective companies.