We have been discussing about this but we don't know the reason of creating a viewmodel factory to create a viewmodel instead of instantiate the viewmodel directly. What is the gain of creating a factory that just creates the viewmodel?
I just put a simple example of how I did it without Factory
here is the kodein module:
val heroesRepositoryModel = Kodein { bind<HeroesRepository>() with singleton { HeroesRepository() } bind<ApiDataSource>() with singleton { DataModule.create() } bind<MainViewModel>() with provider { MainViewModel() } }
The piece of the Activity where I instantiate the viewmodel without using the factory
class MainActivity : AppCompatActivity() { private lateinit var heroesAdapter: HeroAdapter private lateinit var viewModel: MainViewModel private val heroesList = mutableListOf<Heroes.MapHero>() private var page = 0 private var progressBarUpdated = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) viewModel = ViewModelProviders.of(this) .get(MainViewModel::class.java) initAdapter() initObserver() findHeroes() }
The ViewModel where I instantiate the usecase directly without having it in the constructor
class MainViewModel : ViewModel(), CoroutineScope { private val heroesRepository: HeroesRepository = heroesRepositoryModel.instance() val data = MutableLiveData<List<Heroes.MapHero>>() private var job: Job = Job() override val coroutineContext: CoroutineContext get() = uiContext + job fun getHeroesFromRepository(page: Int) { launch { try { val response = heroesRepository.getHeroes(page).await() data.value = response.data.results.map { it.convertToMapHero() } } catch (e: HttpException) { data.value = null } catch (e: Throwable) { data.value = null } } } override fun onCleared() { super.onCleared() job.cancel() } }
So here a example using factory
class ListFragment : Fragment(), KodeinAware, ContactsAdapter.OnContactListener { override val kodein by closestKodein() private lateinit var adapterContacts: ContactsAdapter private val mainViewModelFactory: MainViewModelFactory by instance() private val mainViewModel: MainViewModel by lazy { activity?.run { ViewModelProviders.of(this, mainViewModelFactory) .get(MainViewModel::class.java) } ?: throw Exception("Invalid Activity") } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_list, container, false) }
The viewmodelfactory:
class MainViewModelFactory (private val getContacts: GetContacts) : ViewModelProvider.Factory { override fun <T : ViewModel?> create(modelClass: Class<T>): T { if (modelClass.isAssignableFrom(MainViewModel::class.java)) { return MainViewModel(getContacts) as T } throw IllegalArgumentException("Unknown ViewModel class") } }
And the viewmodel:
class MainViewModel(private val getContacts: GetContacts) : BaseViewModel() { lateinit var gamesList: LiveData<PagedList<Contact>> var contactsSelectedData: MutableLiveData<List<Contact>> = MutableLiveData() var contactsSelected: ArrayList<Contact> = ArrayList() private val pagedListConfig by lazy { PagedList.Config.Builder() .setEnablePlaceholders(false) .setInitialLoadSizeHint(PAGES_CONTACTS_SIZE) .setPageSize(PAGES_CONTACTS_SIZE) .setPrefetchDistance(PAGES_CONTACTS_SIZE*2) .build() }
Here is the complete first example:
https://github.com/ibanarriolaIT/Marvel/tree/mvvm
And the complete second example:
https://github.com/AdrianMeizoso/Payment-App
Factory Method Pattern is the way to let ViewModel wait for value to initialize or another logic that programmer want and then we pass value into ViewModel on Initialization part. ViewModelFactory uses factory to create objects while Factory method is a method that return the copy of the same class.
The purpose of ViewModel is to encapsulate the data for a UI controller to let the data survive configuration changes. For information about how to load, persist, and manage data across configuration changes, see Saving UI States.
The ViewModel exists from when the you first request a ViewModel (usually in the onCreate the Activity) until the Activity is finished and destroyed. onCreate may be called several times during the life of an Activity, such as when the app is rotated, but the ViewModel survives throughout.
We can not create ViewModel on our own. We need ViewModelProviders utility provided by Android to create ViewModels.
But ViewModelProviders can only instantiate ViewModels with no arg constructor.
So if I have a ViewModel with multiple arguments, then I need to use a Factory that I can pass to ViewModelProviders to use when an instance of MyViewModel is required.
For example -
public class MyViewModel extends ViewModel { private final MyRepo myrepo; public MyViewModel(MyRepo myrepo) { this.myrepo = myrepo; } }
To instantiate this ViewModel, I need to have a factory which ViewModelProviders can use to create its instance.
ViewModelProviders Utility can not create instance of a ViewModel with argument constructor because it does not know how and what objects to pass in the constructor.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With