Зачем нужна фабрика Viewmodel в Android? - PullRequest
0 голосов
/ 29 января 2019

Мы обсуждали это, но мы не знаем причину создания фабрики моделей представления для создания модели представления вместо непосредственного создания модели представления.Какова выгода от создания фабрики, которая просто создает модель представления?

Я просто привел простой пример того, как я это сделал без Factory

, вот модуль kodein:

val heroesRepositoryModel = Kodein {
    bind<HeroesRepository>() with singleton {
        HeroesRepository()
    }

    bind<ApiDataSource>() with singleton {
        DataModule.create()
    }

    bind<MainViewModel>() with provider {
        MainViewModel()
    }
}

Часть Activity, в которой я создаю экземпляр модели представления без использования фабрики

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()
    }

Модель представления, в которой я непосредственно создаю экземпляр сценария использования, не имея его в конструкторе

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()
    }
}

Итак, вот пример использования фабрики

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)
    }

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")
    }
}

И 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()
    }

Вот полный первый пример:

https://github.com/ibanarriolaIT/Marvel/tree/mvvm

И полный второй пример:

https://github.com/AdrianMeizoso/Payment-App

Ответы [ 2 ]

0 голосов
/ 29 января 2019

Мы обсуждали это, но мы не знаем причину создания фабрики моделей представления для создания модели представления вместо непосредственного создания модели представления.Какая выгода от создания фабрики, которая просто создает модель представления?

Поскольку Android предоставит вам новый экземпляр, только если он еще не создан для этого конкретного LifecycleOwner .

Давайте также не будем забывать, что ViewModel сохраняются при изменениях конфигурации, поэтому, если вы поворачиваете телефон, вы не должны создавать новую ViewModel.

Если вы возвращаетесь к предыдущемуActivity, и вы снова открываете эту Activity, тогда предыдущая ViewModel должна получить onCleared(), а новая Activity должна иметь новую ViewModel.

Если вы не делаете это самостоятельно, вам, вероятно, следует просто доверять ViewModelProviders.Factory чтобы выполнить свою работу.

(И вам нужна фабрика, потому что у вас обычно нет просто no-arg конструктора, у вашего ViewModel есть аргументы конструктора, и ViewModelProvider должен знать, как заполнитьаргументы конструктора, когда вы используете конструктор не по умолчанию).

0 голосов
/ 29 января 2019

Мы не можем создать ViewModel самостоятельно.Нам нужна утилита ViewModelProviders, предоставляемая Android для создания ViewModels.

Но ViewModelProviders может только создавать экземпляры ViewModels без конструктора arg.

Так что если у меня есть ViewModel с несколькими аргументами, то мне нужно использоватьФабрика, которую я могу передать ViewModelProviders для использования, когда требуется экземпляр MyViewModel.

Например -

public class MyViewModel extends ViewModel {
    private final MyRepo myrepo;
    public MyViewModel(MyRepo myrepo) {
         this.myrepo = myrepo;
    }
}

Чтобы создать экземпляр этой модели ViewModel, мне нужно иметь фабрику, которую могут использовать ViewModelProviders.создать его экземпляр.

Утилита ViewModelProviders не может создать экземпляр ViewModel с помощью конструктора аргументов, поскольку она не знает, как и какие объекты передавать в конструктор.

...