Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
214 views
in Technique[技术] by (71.8m points)

android - Generic Parameterized Base ViewModel

I have following Base class for my ViewModels :

abstract class BaseViewModel<T, R>(private val schedulerProvider: BaseSchedulerProvider) :
    ViewModel() {

    private val compositeDisposable = CompositeDisposable()

    private val _liveData = MutableLiveData<Resource<T>>()
    val liveData: LiveData<Resource<T>>
        get() = _liveData

    protected abstract val requestObservable: Observable<R>

    protected abstract fun getSuccessResult(it: R): T

    init {
        Handler().postDelayed({
            sendRequest()
        }, 1)
    }

    fun sendRequest() {
        _liveData.value = Resource.Loading()
        composeObservable { requestObservable }
            .subscribe({
                _liveData.postValue(Resource.Success(getSuccessResult(it)))
            }) {
                _liveData.postValue(Resource.Failure(it.localizedMessage))
                Timber.e(it)
            }.also { compositeDisposable.add(it) }
    }

    private fun <T> composeObservable(task: () -> Observable<T>): Observable<T> = task()
        .doOnSubscribe { EspressoIdlingResource.increment() } // App is busy until further notice
        .subscribeOn(schedulerProvider.io())
        .observeOn(schedulerProvider.ui())
        .doFinally {
            if (!EspressoIdlingResource.countingIdlingResource.isIdleNow) {
                EspressoIdlingResource.decrement() // Set app as idle.
            }
        }

Here is How I initialize ViewModel in Fragment :

class MainFragment @Inject
constructor() // Required empty public constructor
    : DaggerFragment() {

    @Inject
    lateinit var factory: MainViewModel.Factory

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
    ): View? {

            val viewModel = ViewModelProvider(this, factory).get(MainViewModel::class.java)
}

As you see I have following in init block to delay :

Handler().postDelayed({
                sendRequest()
            }, 1)

Without this delay app crashes since api will be null in the inherited class :

    class MainViewModel(
        api: PokemonService,
        schedulerProvider: BaseSchedulerProvider
    ) : BaseViewModel<List<Pokemon>, List<NamedResponseModel>>(schedulerProvider) {

override val requestObservable: Observable<List<NamedResponseModel>> =
        api.getPokemonList(LIMIT).map { it.results }
}

If I do not use generic parameterized ViewModel, there is no need for delay. You can find repository at : https://github.com/Ali-Rezaei/Pokemon

Why do I need a delay, and what is the solution to avoid delay?

question from:https://stackoverflow.com/questions/65926403/generic-parameterized-base-viewmodel

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The problem is about the initializer's execution order of class. Here is the quote from this article.

First, default constructor arguments are evaluated, starting with argument to the constructor you call directly, followed by arguments to any delegated constructors. Next, initializers (property initializers and init blocks) are executed in the order that they are defined in the class, top-to-bottom. Finally, constructors are executed, starting with the primary constructor and moving outward through delegated constructors until the constructor that you called is executed. The constructor order is probably the most surprising, since no matter where in the class the constructor is defined, it is always executed after all initializers have run.

Please check the article for detailed information.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...