Skip to content

Commit

Permalink
Improve the ViewModel creation approach.
Browse files Browse the repository at this point in the history
  • Loading branch information
arthur3486 committed May 16, 2019
1 parent 332831f commit 1083075
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@

package com.arthurivanets.sample.di.modules.activities

import androidx.lifecycle.ViewModelProviders
import com.arthurivanets.mvvm.ViewModelProviderFactory
import com.arthurivanets.mvvm.util.provideViewModel
import com.arthurivanets.sample.ui.host.HostActivity
import com.arthurivanets.sample.ui.host.HostActivityViewModel
import com.arthurivanets.sample.ui.host.HostActivityViewModelImpl
Expand All @@ -30,8 +29,9 @@ class HostModule {

@Provides
fun provideHostViewModel(activity : HostActivity) : HostActivityViewModel {
val viewModelFactory = ViewModelProviderFactory(HostActivityViewModelImpl())
return ViewModelProviders.of(activity, viewModelFactory).get(HostActivityViewModelImpl::class.java)
return activity.provideViewModel(HostActivityViewModelImpl::class.java) {
HostActivityViewModelImpl()
}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@

package com.arthurivanets.sample.di.modules.fragments

import androidx.lifecycle.ViewModelProviders
import com.arthurivanets.mvvm.ViewModelProviderFactory
import com.arthurivanets.mvvm.util.provideViewModel
import com.arthurivanets.sample.domain.repositories.characters.CharactersRepository
import com.arthurivanets.sample.ui.characters.info.CharacterInfoFragment
import com.arthurivanets.sample.ui.characters.info.CharacterInfoViewModel
Expand All @@ -35,16 +34,18 @@ class CharactersModule {
@Provides
fun provideCharactersViewModel(fragment : CharactersFragment,
charactersRepository : CharactersRepository) : CharactersViewModel {
val viewModelFactory = ViewModelProviderFactory(CharactersViewModelImpl(charactersRepository))
return ViewModelProviders.of(fragment, viewModelFactory).get(CharactersViewModelImpl::class.java)
return fragment.provideViewModel(CharactersViewModelImpl::class.java) {
CharactersViewModelImpl(charactersRepository)
}
}


@Provides
fun provideCharacterInfoViewModel(fragment : CharacterInfoFragment,
charactersRepository : CharactersRepository) : CharacterInfoViewModel {
val viewModelFactory = ViewModelProviderFactory(CharacterInfoViewModelImpl(charactersRepository))
return ViewModelProviders.of(fragment, viewModelFactory).get(CharacterInfoViewModelImpl::class.java)
return fragment.provideViewModel(CharacterInfoViewModelImpl::class.java) {
CharacterInfoViewModelImpl(charactersRepository)
}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@

package com.arthurivanets.sample.di.modules.fragments

import androidx.lifecycle.ViewModelProviders
import com.arthurivanets.mvvm.ViewModelProviderFactory
import com.arthurivanets.mvvm.util.provideViewModel
import com.arthurivanets.sample.domain.repositories.comics.ComicsRepository
import com.arthurivanets.sample.ui.comics.info.ComicsInfoFragment
import com.arthurivanets.sample.ui.comics.info.ComicsInfoViewModel
Expand All @@ -35,16 +34,18 @@ class ComicsModule {
@Provides
fun provideComicsViewModel(fragment : ComicsFragment,
comicsRepository : ComicsRepository) : ComicsViewModel {
val viewModelFactory = ViewModelProviderFactory(ComicsViewModelImpl(comicsRepository))
return ViewModelProviders.of(fragment, viewModelFactory).get(ComicsViewModelImpl::class.java)
return fragment.provideViewModel(ComicsViewModelImpl::class.java) {
ComicsViewModelImpl(comicsRepository)
}
}


@Provides
fun provideComicsInfoViewModel(fragment : ComicsInfoFragment,
comicsRepository : ComicsRepository) : ComicsInfoViewModel {
val viewModelFactory = ViewModelProviderFactory(ComicsInfoViewModelImpl(comicsRepository))
return ViewModelProviders.of(fragment, viewModelFactory).get(ComicsInfoViewModelImpl::class.java)
return fragment.provideViewModel(ComicsInfoViewModelImpl::class.java) {
ComicsInfoViewModelImpl(comicsRepository)
}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@

package com.arthurivanets.sample.di.modules.fragments

import androidx.lifecycle.ViewModelProviders
import com.arthurivanets.mvvm.ViewModelProviderFactory
import com.arthurivanets.mvvm.util.provideViewModel
import com.arthurivanets.sample.ui.dashboard.DashboardFragment
import com.arthurivanets.sample.ui.dashboard.DashboardViewModel
import com.arthurivanets.sample.ui.dashboard.DashboardViewModelImpl
Expand All @@ -30,8 +29,9 @@ class DashboardModule {

@Provides
fun provideDashboardViewModel(fragment : DashboardFragment) : DashboardViewModel {
val viewModelFactory = ViewModelProviderFactory(DashboardViewModelImpl())
return ViewModelProviders.of(fragment, viewModelFactory).get(DashboardViewModelImpl::class.java)
return fragment.provideViewModel(DashboardViewModelImpl::class.java) {
DashboardViewModelImpl()
}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@

package com.arthurivanets.sample.di.modules.fragments

import androidx.lifecycle.ViewModelProviders
import com.arthurivanets.mvvm.ViewModelProviderFactory
import com.arthurivanets.mvvm.util.provideViewModel
import com.arthurivanets.sample.domain.repositories.events.EventsRepository
import com.arthurivanets.sample.ui.events.info.EventInfoFragment
import com.arthurivanets.sample.ui.events.info.EventInfoViewModel
Expand All @@ -35,16 +34,18 @@ class EventsModule {
@Provides
fun provideEventsViewModel(fragment : EventsFragment,
eventsRepository : EventsRepository) : EventsViewModel {
val viewModelFactory = ViewModelProviderFactory(EventsViewModelImpl(eventsRepository))
return ViewModelProviders.of(fragment, viewModelFactory).get(EventsViewModelImpl::class.java)
return fragment.provideViewModel(EventsViewModelImpl::class.java) {
EventsViewModelImpl(eventsRepository)
}
}


@Provides
fun provideEventInfoViewModel(fragment : EventInfoFragment,
eventsRepository : EventsRepository) : EventInfoViewModel {
val viewModelFactory = ViewModelProviderFactory(EventInfoViewModelImpl(eventsRepository))
return ViewModelProviders.of(fragment, viewModelFactory).get(EventInfoViewModelImpl::class.java)
return fragment.provideViewModel(EventInfoViewModelImpl::class.java) {
EventInfoViewModelImpl(eventsRepository)
}
}


Expand Down
4 changes: 2 additions & 2 deletions common/constants.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ project.ext {
releaseRepoName = "maven"
releaseUserOrg = "arthurlabs"
releaseGroupId = "com.arthurivanets.mvvm"
releaseVersion = "1.0.0"
releaseVersionCode = 1
releaseVersion = "1.1.0"
releaseVersionCode = 2
releaseWebsite = "https://github.com/arthur3486/android-mvvm"
releaseLicense = ["Apache-2.0"]

Expand Down
1 change: 1 addition & 0 deletions mvvm/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ dependencies {

implementation kotlinDependencies
implementation androidCoreDependencies
implementation lifecycleDependencies

implementation rxJavaDependencies
implementation rxBusDependencies
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,20 @@ import androidx.lifecycle.ViewModelProvider
* <br>
* Allows you to construct the [ViewModel] that meets your requirements (e.g. perform the dependency injection into your [ViewModel]).
*/
class ViewModelProviderFactory<V : ViewModel>(private val viewModel : V) : ViewModelProvider.Factory {


class ViewModelProviderFactory<V : ViewModel>(
private val viewModelClass : Class<V>,
private val creator : () -> V
) : ViewModelProvider.Factory {


@SuppressWarnings("unchecked")
override fun <T : ViewModel?> create(modelClass : Class<T>) : T {
if(!modelClass.isAssignableFrom(viewModel::class.java)) {
if(!modelClass.isAssignableFrom(viewModelClass)) {
throw IllegalArgumentException("Unsupported class name.")
}

return (viewModel as T)
return (creator() as T)
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2018 Arthur Ivanets, [email protected]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

@file:JvmName("ViewModelProviderUtils")

package com.arthurivanets.mvvm.util

import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProviders
import com.arthurivanets.mvvm.ViewModelProviderFactory


/**
* Provides the [ViewModel] of the specified class using the [ViewModelProviders] and a custom [ViewModelProviderFactory],
* thus allowing you to construct a [ViewModel] according to your requirements (e.g. inject the dependencies into it, etc.).
* The creation of a new [ViewModel] instance using the [creator] will happen only if the [ViewModelProviders] doesn't have
* a retained version of the corresponding [ViewModel] instance, otherwise the existing (retained) [ViewModel] will be reused.
*/
fun <T : ViewModel> FragmentActivity.provideViewModel(viewModelClass : Class<T>, creator : () -> T) : T {
val viewModelFactory = ViewModelProviderFactory(viewModelClass, creator)
return ViewModelProviders.of(this, viewModelFactory).get(viewModelClass)
}


/**
* Provides the [ViewModel] of the specified class using the [ViewModelProviders] and a custom [ViewModelProviderFactory],
* thus allowing you to construct a [ViewModel] according to your requirements (e.g. inject the dependencies into it, etc.).
* The creation of a new [ViewModel] instance using the [creator] will happen only if the [ViewModelProviders] doesn't have
* a retained version of the corresponding [ViewModel] instance, otherwise the existing (retained) [ViewModel] will be reused.
*/
fun <T : ViewModel> Fragment.provideViewModel(viewModelClass : Class<T>, creator : () -> T) : T {
val viewModelFactory = ViewModelProviderFactory(viewModelClass, creator)
return ViewModelProviders.of(this, viewModelFactory).get(viewModelClass)
}

0 comments on commit 1083075

Please sign in to comment.